├── .gitattributes
├── .gitignore
├── toolchain
├── win
│ ├── stamp.py
│ ├── recursive_mirror.py
│ ├── asm_wrapper.py
│ ├── message_compiler.py
│ ├── midl_wrapper.py
│ ├── link_wrapper.py
│ ├── rc_wrapper.py
│ ├── message_compiler.gni
│ ├── midl.gni
│ ├── manifest.gni
│ └── settings.gni
├── clang_static_analyzer.gni
├── BUILD.gn
├── mac
│ ├── mac_sdk_overrides.gni
│ ├── settings.gni
│ ├── BUILD.gn
│ ├── find_sdk.py
│ └── mac_sdk.gni
├── apple
│ ├── get_tool_mtime.py
│ ├── BUILD.gn
│ ├── symbols.gni
│ ├── filter_libtool.py
│ ├── sdk_info.py
│ └── linker_driver.py
├── concurrent_links.gni
├── clang.gni
├── cc_wrapper.gni
├── posix
│ ├── settings.gni
│ ├── toolchain.py
│ └── BUILD.gn
├── gcc_compile_wrapper.py
├── coverage.gni
├── sysroot.gni
├── toolchain.gni
├── gcc_ar_wrapper.py
├── compiler_version.gni
├── clang_static_analyzer_wrapper.py
├── gcc_link_wrapper.py
├── gcc_solink_wrapper.py
├── android
│ ├── BUILD.gn
│ └── settings.gni
└── wrapper_utils.py
├── apple
├── README.md
├── convert_plist.gni
├── xcrun.py
├── compile_entitlements.gni
├── write_pkg_info.py
├── apple_info_plist.gni
├── compile_plist.gni
└── plist_util.py
├── mac
├── BuildInfo.plist
├── prepare_framework_version.py
└── package_framework.py
├── gn_run_binary.py
├── config
├── mips.gni
├── ios
│ └── BUILD.gn
├── posix
│ └── BUILD.gn
├── precompiled_header.gni
├── compiler.gni
├── libc++
│ ├── settings.gni
│ └── BUILD.gn
├── arm.gni
├── mac
│ └── BUILD.gn
├── android
│ └── BUILD.gn
└── sanitizers
│ └── sanitizers.gni
├── .github
└── workflows
│ ├── windows.yml
│ └── posix.yml
├── compiled_action.gni
├── README.md
└── gn_helpers_unittest.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
3 | *.py text
4 | *.gn text
5 | *.gni text
6 |
7 | *.sh text eol=lf
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Python artifacts (bytecode, PyCharm projects, ...)
2 | /.idea
3 | /__pycache__
4 | *.pyc
5 |
--------------------------------------------------------------------------------
/toolchain/win/stamp.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 |
4 | def main(path):
5 | """Simple stamp command."""
6 | open(path, 'w').close()
7 |
8 | if __name__ == '__main__':
9 | sys.exit(main(*sys.argv[1:]))
10 |
--------------------------------------------------------------------------------
/toolchain/clang_static_analyzer.gni:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # Defines the configuration of Clang static analysis tools.
6 | # See docs/clang_static_analyzer.md for more information.
7 |
8 | declare_args() {
9 | # Uses the Clang static analysis tools during compilation.
10 | use_clang_static_analyzer = false
11 | }
12 |
--------------------------------------------------------------------------------
/toolchain/BUILD.gn:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/concurrent_links.gni")
6 |
7 | declare_args() {
8 | # Pool for action tasks.
9 | action_pool_depth = 0
10 | }
11 |
12 | if (current_toolchain == default_toolchain) {
13 | pool("link_pool") {
14 | depth = concurrent_links
15 | }
16 |
17 | pool("action_pool") {
18 | depth = action_pool_depth
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/apple/README.md:
--------------------------------------------------------------------------------
1 | # About
2 |
3 | `//build/apple` contains:
4 | * GN templates and configurations shared by Apple platforms
5 | * Python build scripts shared by Apple platforms
6 |
7 | This directory should only contain templates, configurations and scripts
8 | that are used exclusively on Apple platforms (currently iOS and macOS).
9 | They must also be independent of the specific platform.
10 |
11 | If a template, configuration or script is limited to only iOS or macOS,
12 | then they should instead be located in `//build/ios` or `//build/mac`.
13 |
--------------------------------------------------------------------------------
/mac/BuildInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DTCompiler
6 | ${GCC_VERSION}
7 | DTSDKBuild
8 | ${MAC_SDK_BUILD}
9 | DTSDKName
10 | ${MAC_SDK_NAME}
11 | DTXcode
12 | ${XCODE_VERSION}
13 | DTXcodeBuild
14 | ${XCODE_BUILD}
15 |
16 |
17 |
--------------------------------------------------------------------------------
/toolchain/mac/mac_sdk_overrides.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2017 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # This file contains arguments that subprojects may choose to override. It
6 | # asserts that those overrides are used, to prevent unused args warnings.
7 |
8 | _sdk_min_from_env = getenv("FORCE_MAC_SDK_MIN")
9 | declare_args() {
10 | # Minimum supported version of the Mac SDK.
11 | if (_sdk_min_from_env == "") {
12 | mac_sdk_min = "10.10"
13 | } else {
14 | mac_sdk_min = _sdk_min_from_env
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/toolchain/apple/get_tool_mtime.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | from __future__ import print_function
6 |
7 | import os
8 | import sys
9 |
10 | # Usage: python get_tool_mtime.py path/to/file1.py path/to/file2.py
11 | #
12 | # Prints a GN scope with the variable name being the basename sans-extension
13 | # and the value being the file modification time. A variable is emitted for
14 | # each file argument on the command line.
15 |
16 | if __name__ == '__main__':
17 | for f in sys.argv[1:]:
18 | variable = os.path.splitext(os.path.basename(f))[0]
19 | print('%s = %d' % (variable, os.path.getmtime(f)))
20 |
--------------------------------------------------------------------------------
/toolchain/apple/BUILD.gn:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/concurrent_links.gni")
6 |
7 | declare_args() {
8 | # Reduce the number of tasks using the copy_bundle_data and compile_xcassets
9 | # tools as they can cause lots of I/O contention when invoking ninja with a
10 | # large number of parallel jobs (e.g. when using distributed build like goma).
11 | bundle_pool_depth = -1
12 | }
13 |
14 | if (current_toolchain == default_toolchain) {
15 | pool("bundle_pool") {
16 | if (bundle_pool_depth == -1) {
17 | depth = concurrent_links
18 | } else {
19 | depth = bundle_pool_depth
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/toolchain/mac/settings.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # These variables used to live here
6 | import("//build/toolchain/apple/symbols.gni")
7 |
8 | declare_args() {
9 | # Use the system install of Xcode for tools like ibtool, libtool, etc.
10 | # This does not affect the compiler. When this variable is false, targets will
11 | # instead use a hermetic install of Xcode.
12 | use_system_xcode = true
13 |
14 | # The path to the hermetic install of Xcode. Only relevant when
15 | # use_system_xcode = false.
16 | hermetic_xcode_path = ""
17 |
18 | # Compile with Xcode version of clang instead of hermetic version shipped
19 | # with the build.
20 | use_xcode_clang = true
21 | }
22 |
--------------------------------------------------------------------------------
/toolchain/concurrent_links.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # This file should only be imported from files that define toolchains.
6 | # There's no way to enforce this exactly, but all toolchains are processed
7 | # in the context of the default_toolchain, so we can at least check for that.
8 | assert(current_toolchain == default_toolchain)
9 |
10 | declare_args() {
11 | # Limit the number of concurrent links; we often want to run fewer
12 | # links at once than we do compiles, because linking is memory-intensive.
13 | # The default to use varies by platform and by the amount of memory
14 | # available, so we call out to a script to get the right value.
15 | concurrent_links = 0
16 | }
17 |
--------------------------------------------------------------------------------
/toolchain/win/recursive_mirror.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import shutil
4 | import sys
5 |
6 | def main(source, dest):
7 | """Emulation of rm -rf out && cp -af in out."""
8 | if os.path.exists(dest):
9 | if os.path.isdir(dest):
10 | def _on_error(fn, path, excinfo):
11 | # The operation failed, possibly because the file is set to
12 | # read-only. If that's why, make it writable and try the op again.
13 | if not os.access(path, os.W_OK):
14 | os.chmod(path, stat.S_IWRITE)
15 | fn(path)
16 | shutil.rmtree(dest, onerror=_on_error)
17 | else:
18 | if not os.access(dest, os.W_OK):
19 | # Attempt to make the file writable before deleting it.
20 | os.chmod(dest, stat.S_IWRITE)
21 | os.unlink(dest)
22 |
23 | if os.path.isdir(source):
24 | shutil.copytree(source, dest)
25 | else:
26 | shutil.copy2(source, dest)
27 |
28 | if __name__ == '__main__':
29 | sys.exit(main(*sys.argv[1:]))
30 |
--------------------------------------------------------------------------------
/toolchain/clang.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # Toolchain-related configuration that may be needed outside the context of the
6 | # toolchain() rules themselves.
7 |
8 | declare_args() {
9 | # The path of your Clang installation folder (without /bin).
10 | clang_base_path = ""
11 |
12 | # Set to true to use lld, the LLVM linker.
13 | use_lld = false
14 |
15 | # Enables the experimental support of ThinLTO that links 3x-10x faster but
16 | # (as of now) does not have all the important optimizations such us
17 | # devirtualization implemented. See also
18 | # http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html
19 | # TODO(tim): Supported on Windows?
20 | use_thin_lto = false
21 | }
22 |
23 | if (is_win && is_clang) {
24 | assert(clang_base_path != "",
25 | "You must set clang_base_path when using Clang on Windows")
26 | }
27 |
--------------------------------------------------------------------------------
/toolchain/cc_wrapper.gni:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # Defines the configuration of cc wrapper
6 | # ccache: a c/c++ compiler cache which can greatly reduce recompilation times.
7 | # icecc, distcc: it takes compile jobs from a build and distributes them among
8 | # remote machines allowing a parallel build.
9 | #
10 | # TIPS
11 | #
12 | # 1) ccache
13 | # Use ccache 3.2 or later to avoid clang unused argument warnings:
14 | # https://bugzilla.samba.org/show_bug.cgi?id=8118
15 | #
16 | # To avoid -Wparentheses-equality clang warnings, at some cost in terms of
17 | # speed, you can do:
18 | # export CCACHE_CPP2=yes
19 | #
20 | # 2) icecc
21 | # To use icecc and ccache together, set cc_wrapper = "ccache" with
22 | # export CCACHE_PREFIX=icecc
23 |
24 | declare_args() {
25 | # Set to "ccache", "icecc" or "distcc". Probably doesn't work on windows.
26 | cc_wrapper = ""
27 | }
28 |
--------------------------------------------------------------------------------
/toolchain/posix/settings.gni:
--------------------------------------------------------------------------------
1 | if (is_clang) {
2 | import("//build/toolchain/clang.gni")
3 | }
4 |
5 | declare_args() {
6 | # Path of the GCC C compiler executable.
7 | gcc_cc = "gcc"
8 |
9 | # Path of the GCC C++ compiler executable.
10 | gcc_cxx = "g++"
11 |
12 | # Path of the Clang C compiler executable.
13 | # Defaults to either $clang_base_path/bin/clang or clang.
14 | clang_cc = 0
15 |
16 | # Path of the Clang C++ compiler executable.
17 | # Defaults to either $clang_base_path/bin/clang++ or clang++.
18 | clang_cxx = 0
19 |
20 | # Path of the 'readelf' utility.
21 | readelf = "readelf"
22 |
23 | # Path of the 'ar' utility.
24 | ar = "ar"
25 |
26 | # Path of the 'nm' utility.
27 | nm = "nm"
28 | }
29 |
30 | if (is_clang && clang_cc == 0) {
31 | if (clang_base_path != "") {
32 | clang_cc = "$clang_base_path/clang"
33 | } else {
34 | clang_cc = "clang"
35 | }
36 | }
37 |
38 | if (is_clang && clang_cxx == 0) {
39 | if (clang_base_path != "") {
40 | clang_cxx = "$clang_base_path/clang++"
41 | } else {
42 | clang_cxx = "clang++"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/toolchain/win/asm_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import subprocess
3 | import sys
4 | from toolchain import GetEnv
5 |
6 |
7 | def main(arch, *args):
8 | """Filter logo banner from invocations of asm.exe."""
9 | env = GetEnv(arch)
10 | if sys.platform == 'win32':
11 | # Windows ARM64 uses clang-cl as assembler which has '/' as path
12 | # separator, convert it to '\\' when running on Windows.
13 | args = list(args) # *args is a tuple by default, which is read-only
14 | args[0] = args[0].replace('/', '\\')
15 | popen = subprocess.Popen(args, shell=True, env=env, universal_newlines=True,
16 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
17 | out, _ = popen.communicate()
18 | for line in out.splitlines():
19 | if (not line.startswith('Copyright (C) Microsoft Corporation') and
20 | not line.startswith('Microsoft (R) Macro Assembler') and
21 | not line.startswith(' Assembling: ') and
22 | line):
23 | print(line)
24 | return popen.returncode
25 |
26 | if __name__ == '__main__':
27 | sys.exit(main(*sys.argv[1:]))
28 |
--------------------------------------------------------------------------------
/toolchain/win/message_compiler.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
6 | # GN build, which can only run Python and not native binaries.
7 | #
8 | # Usage: message_compiler.py [*]
9 |
10 | import subprocess
11 | import sys
12 |
13 | # Read the environment block from the file. This is stored in the format used
14 | # by CreateProcess. Drop last 2 NULs, one for list terminator, one for trailing
15 | # vs. separator.
16 | env_pairs = open(sys.argv[1]).read()[:-2].split('\0')
17 | env_dict = dict([item.split('=', 1) for item in env_pairs])
18 |
19 | # mc writes to stderr, so this explicitly redirects to stdout and eats it.
20 | try:
21 | # This needs shell=True to search the path in env_dict for the mc executable.
22 | subprocess.check_output(["mc.exe"] + sys.argv[2:],
23 | env=env_dict,
24 | stderr=subprocess.STDOUT,
25 | shell=True, universal_newlines=True)
26 | except subprocess.CalledProcessError as e:
27 | print e.output
28 | sys.exit(e.returncode)
29 |
--------------------------------------------------------------------------------
/gn_run_binary.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | """Helper script for GN to run an arbitrary binary. See compiled_action.gni.
6 |
7 | Run with:
8 | python gn_run_binary.py [args ...]
9 | """
10 |
11 | from __future__ import print_function
12 |
13 | import os
14 | import subprocess
15 | import sys
16 |
17 | # This script is designed to run binaries produced by the current build. We
18 | # may prefix it with "./" to avoid picking up system versions that might
19 | # also be on the path.
20 | path = sys.argv[1]
21 | if not os.path.isabs(path):
22 | path = './' + path
23 |
24 | # The rest of the arguments are passed directly to the executable.
25 | args = [path] + sys.argv[2:]
26 |
27 | ret = subprocess.call(args)
28 | if ret != 0:
29 | if ret <= -100:
30 | # Windows error codes such as 0xC0000005 and 0xC0000409 are much easier to
31 | # recognize and differentiate in hex. In order to print them as unsigned
32 | # hex we need to add 4 Gig to them.
33 | print('%s failed with exit code 0x%08X' % (sys.argv[1], ret + (1 << 32)))
34 | else:
35 | print('%s failed with exit code %d' % (sys.argv[1], ret))
36 | sys.exit(ret)
37 |
--------------------------------------------------------------------------------
/toolchain/win/midl_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import subprocess
4 | import sys
5 | from toolchain import GetEnv
6 |
7 |
8 | def main(arch, outdir, tlb, h, dlldata, iid, proxy, idl, *flags):
9 | """Filter noisy filenames output from MIDL compile step that isn't
10 | quietable via command line flags.
11 | """
12 | args = ['midl', '/nologo'] + list(flags) + [
13 | '/out', outdir,
14 | '/tlb', tlb,
15 | '/h', h,
16 | '/dlldata', dlldata,
17 | '/iid', iid,
18 | '/proxy', proxy,
19 | idl]
20 | env = GetEnv(arch)
21 | popen = subprocess.Popen(args, shell=True, env=env, universal_newlines=True,
22 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
23 | out, _ = popen.communicate()
24 | # Filter junk out of stdout, and write filtered versions. Output we want
25 | # to filter is pairs of lines that look like this:
26 | # Processing C:\Program Files (x86)\Microsoft SDKs\...\include\objidl.idl
27 | # objidl.idl
28 | lines = out.splitlines()
29 | prefixes = ('Processing ', '64 bit Processing ')
30 | processing = set(os.path.basename(x)
31 | for x in lines if x.startswith(prefixes))
32 | for line in lines:
33 | if not line.startswith(prefixes) and line not in processing:
34 | print(line)
35 | return popen.returncode
36 |
37 | if __name__ == '__main__':
38 | sys.exit(main(*sys.argv[1:]))
39 |
--------------------------------------------------------------------------------
/toolchain/apple/symbols.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # This file declares arguments and configs that control whether dSYM debug
6 | # info is produced and whether build products are stripped.
7 |
8 | declare_args() {
9 | # Produce dSYM files for targets that are configured to do so. dSYM
10 | # generation is controlled globally as it is a linker output (produced via
11 | # the //build/toolchain/apple/linker_driver.py. Enabling this will result in
12 | # all shared library, loadable module, and executable targets having a dSYM
13 | # generated.
14 | enable_dsyms = is_official_build
15 |
16 | # Strip symbols from linked targets by default. If this is enabled, the
17 | # //build/config/mac:strip_all config will be applied to all linked targets.
18 | # If custom stripping parameters are required, remove that config from a
19 | # linked target and apply custom -Wcrl,strip flags. See
20 | # //build/toolchain/apple/linker_driver.py for more information.
21 | enable_stripping = is_official_build
22 | }
23 |
24 | # Save unstripped copies of targets with a ".unstripped" suffix. This is
25 | # useful to preserve the original output when enable_stripping=true but
26 | # we're not actually generating real dSYMs.
27 | save_unstripped_output = enable_stripping && !enable_dsyms
28 |
--------------------------------------------------------------------------------
/apple/convert_plist.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # Convert plist file to given format.
6 | #
7 | # Arguments
8 | #
9 | # source:
10 | # string, path to the plist file to convert
11 | #
12 | # output:
13 | # string, path to the converted plist, must be under $root_build_dir
14 | #
15 | # format:
16 | # string, the format to convert the plist to. Either "binary1" or "xml1".
17 | template("convert_plist") {
18 | assert(defined(invoker.source), "source must be defined for $target_name")
19 | assert(defined(invoker.output), "output must be defined for $target_name")
20 | assert(defined(invoker.format), "format must be defined for $target_name")
21 |
22 | action(target_name) {
23 | forward_variables_from(invoker,
24 | [
25 | "visibility",
26 | "testonly",
27 | "deps",
28 | ])
29 |
30 | script = "//build/apple/plist_util.py"
31 | sources = [ invoker.source ]
32 | outputs = [ invoker.output ]
33 | args = [
34 | "merge",
35 | "--format=${invoker.format}",
36 | "-o",
37 | rebase_path(invoker.output, root_build_dir),
38 | rebase_path(invoker.source, root_build_dir),
39 | ]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/toolchain/gcc_compile_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2016 The Chromium Authors. All rights reserved.
3 | # Use of this source code is governed by a BSD-style license that can be
4 | # found in the LICENSE file.
5 |
6 | """Runs a compilation command.
7 |
8 | This script exists to avoid using complex shell commands in
9 | gcc_toolchain.gni's tool("cxx") and tool("cc") in case the host running the
10 | compiler does not have a POSIX-like shell (e.g. Windows).
11 | """
12 |
13 | import argparse
14 | import sys
15 |
16 | import wrapper_utils
17 |
18 |
19 | def main():
20 | parser = argparse.ArgumentParser(description=__doc__)
21 | parser.add_argument('--resource-whitelist',
22 | help='Generate a resource whitelist for this target.',
23 | metavar='PATH')
24 | parser.add_argument('command', nargs=argparse.REMAINDER,
25 | help='Compilation command')
26 | args = parser.parse_args()
27 |
28 | returncode, stderr = wrapper_utils.CaptureCommandStderr(
29 | wrapper_utils.CommandToRun(args.command))
30 |
31 | used_resources = wrapper_utils.ExtractResourceIdsFromPragmaWarnings(stderr)
32 | sys.stderr.write(stderr)
33 |
34 | if args.resource_whitelist:
35 | with open(args.resource_whitelist, 'w') as f:
36 | if used_resources:
37 | f.write('\n'.join(str(resource) for resource in used_resources))
38 | f.write('\n')
39 |
40 | return returncode
41 |
42 | if __name__ == "__main__":
43 | sys.exit(main())
44 |
--------------------------------------------------------------------------------
/mac/prepare_framework_version.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import os
6 | import shutil
7 | import sys
8 |
9 | # Ensures that the current version matches the last-produced version, which is
10 | # stored in the version_file. If it does not, then the framework_root_dir is
11 | # obliterated.
12 | # Usage: python prepare_framework_version.py out/obj/version_file \
13 | # out/Framework.framework \
14 | # 'A'
15 |
16 | def PrepareFrameworkVersion(version_file, framework_root_dir, version):
17 | # Test what the current framework version is. Stop if it is up-to-date.
18 | try:
19 | with open(version_file, 'r') as f:
20 | current_version = f.read()
21 | if current_version == version:
22 | return
23 | except IOError:
24 | pass
25 |
26 | # The framework version has changed, so clobber the framework.
27 | if os.path.exists(framework_root_dir):
28 | shutil.rmtree(framework_root_dir)
29 |
30 | # Write out the new framework version file, making sure its containing
31 | # directory exists.
32 | dirname = os.path.dirname(version_file)
33 | if not os.path.isdir(dirname):
34 | os.makedirs(dirname, 0o700)
35 |
36 | with open(version_file, 'w+') as f:
37 | f.write(version)
38 |
39 |
40 | if __name__ == '__main__':
41 | PrepareFrameworkVersion(sys.argv[1], sys.argv[2], sys.argv[3])
42 | sys.exit(0)
43 |
--------------------------------------------------------------------------------
/toolchain/coverage.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2017 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/toolchain.gni")
6 |
7 | # There are two ways to enable code coverage instrumentation:
8 | # 1. When |use_clang_coverage| or |use_jacoco_coverage| is true and
9 | # |coverage_instrumentation_input_file| is empty, all source files or
10 | # Java class files are instrumented.
11 | # 2. When |use_clang_coverage| or |use_jacoco_coverage| is true and
12 | # |coverage_instrumentation_input_file| is NOT empty and points to
13 | # a text file on the file system, ONLY source files specified in the
14 | # input file or Java class files related to source files are instrumented.
15 | declare_args() {
16 | # Enable Clang's Source-based Code Coverage.
17 | use_clang_coverage = false
18 |
19 | # Enables JaCoCo Java code coverage.
20 | use_jacoco_coverage = false
21 |
22 | # The path to the coverage instrumentation input file should be a source root
23 | # absolute path (e.g. //out/Release/coverage_instrumentation_input.txt), and
24 | # the file consists of multiple lines where each line represents a path to a
25 | # source file, and the paths must be relative to the root build directory.
26 | # e.g. ../../base/task/post_task.cc for build directory 'out/Release'.
27 | #
28 | # NOTE that this arg will be non-op if use_clang_coverage is false.
29 | coverage_instrumentation_input_file = ""
30 | }
31 |
32 | assert(!use_clang_coverage || is_clang,
33 | "Clang Source-based Code Coverage requires clang.")
34 |
--------------------------------------------------------------------------------
/toolchain/posix/toolchain.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from __future__ import print_function
3 |
4 | import re
5 | import subprocess
6 | import sys
7 | import os
8 |
9 | def _get_compiler_version(path, major_define, minor_define, patchlevel_define):
10 | path = os.path.normpath(path)
11 | defines = subprocess.check_output('echo "" | "{}" -dM -E -'.format(path), shell=True,
12 | universal_newlines=True).split('\n')
13 | version = 0
14 | for define in defines:
15 | define = re.findall(r'#define ([a-zA-Z0-9_]+) (.*)', define)
16 | if not define:
17 | continue
18 |
19 | name, value = define[0]
20 | if name == major_define:
21 | version += 10000 * int(value)
22 | elif name == minor_define:
23 | version += 100 * int(value)
24 | elif name == patchlevel_define:
25 | value = int(value)
26 | if value < 100:
27 | version += int(value)
28 |
29 | return version
30 |
31 |
32 | def get_gcc_version(path):
33 | print(_get_compiler_version(path, '__GNUC__', '__GNUC_MINOR__', '__GNUC_PATCHLEVEL__'))
34 |
35 |
36 | def get_clang_version(path):
37 | print(_get_compiler_version(path, '__clang_major__', '__clang_minor__', '__clang_patchlevel__'))
38 |
39 |
40 | def main():
41 | commands = {
42 | 'get_gcc_version': get_gcc_version,
43 | 'get_clang_version': get_clang_version,
44 | }
45 |
46 | if len(sys.argv) < 2 or sys.argv[1] not in commands:
47 | print('Expected one of: %s' % ', '.join(commands), file=sys.stderr)
48 | return 1
49 |
50 | return commands[sys.argv[1]](*sys.argv[2:])
51 |
52 |
53 | if __name__ == '__main__':
54 | sys.exit(main())
55 |
--------------------------------------------------------------------------------
/toolchain/sysroot.gni:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # This header file defines the "sysroot" variable which is the absolute path
6 | # of the sysroot. If no sysroot applies, the variable will be an empty string.
7 |
8 | declare_args() {
9 | # The absolute path of the sysroot that is applied when compiling using
10 | # the target toolchain.
11 | target_sysroot = ""
12 |
13 | use_sysroot = false
14 | }
15 |
16 | if (current_os == target_os && current_cpu == target_cpu &&
17 | target_sysroot != "") {
18 | sysroot = target_sysroot
19 | } else if (is_android) {
20 | import("//build/toolchain/android/settings.gni")
21 | if (current_cpu == "x86") {
22 | sysroot = "$android_ndk_root/$x86_android_sysroot_subdir"
23 | } else if (current_cpu == "arm") {
24 | sysroot = "$android_ndk_root/$arm_android_sysroot_subdir"
25 | } else if (current_cpu == "mipsel") {
26 | sysroot = "$android_ndk_root/$mips_android_sysroot_subdir"
27 | } else if (current_cpu == "x64") {
28 | sysroot = "$android_ndk_root/$x86_64_android_sysroot_subdir"
29 | } else if (current_cpu == "arm64") {
30 | sysroot = "$android_ndk_root/$arm64_android_sysroot_subdir"
31 | } else if (current_cpu == "mips64el") {
32 | sysroot = "$android_ndk_root/$mips64_android_sysroot_subdir"
33 | } else {
34 | sysroot = ""
35 | }
36 | } else if (is_mac) {
37 | import("//build/toolchain/mac/mac_sdk.gni")
38 | sysroot = mac_sdk_path
39 | } else if (is_ios) {
40 | import("//build/toolchain/mac/ios_sdk.gni")
41 | sysroot = ios_sdk_path
42 | } else {
43 | sysroot = ""
44 | }
45 |
--------------------------------------------------------------------------------
/apple/xcrun.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # Copyright 2020 The Chromium Authors. All rights reserved.
3 | # Use of this source code is governed by a BSD-style license that can be
4 | # found in the LICENSE file.
5 | """
6 | Wrapper around xcrun adding support for --developer-dir parameter to set
7 | the DEVELOPER_DIR environment variable, and for converting paths relative
8 | to absolute (since this is required by most of the tool run via xcrun).
9 | """
10 |
11 | import argparse
12 | import os
13 | import subprocess
14 | import sys
15 |
16 |
17 | def xcrun(command, developer_dir):
18 | environ = dict(os.environ)
19 | if developer_dir:
20 | environ['DEVELOPER_DIR'] = os.path.abspath(developer_dir)
21 |
22 | processed_args = ['/usr/bin/xcrun']
23 | for arg in command:
24 | if os.path.exists(arg):
25 | arg = os.path.abspath(arg)
26 | processed_args.append(arg)
27 |
28 | process = subprocess.Popen(processed_args,
29 | stdout=subprocess.PIPE,
30 | stderr=subprocess.PIPE,
31 | universal_newlines=True,
32 | env=environ)
33 |
34 | stdout, stderr = process.communicate()
35 | sys.stdout.write(stdout)
36 | if process.returncode:
37 | sys.stderr.write(stderr)
38 | sys.exit(process.returncode)
39 |
40 |
41 | def main(args):
42 | parser = argparse.ArgumentParser(add_help=False)
43 | parser.add_argument(
44 | '--developer-dir',
45 | help='path to developer dir to use for the invocation of xcrun')
46 |
47 | parsed, remaining_args = parser.parse_known_args(args)
48 | xcrun(remaining_args, parsed.developer_dir)
49 |
50 |
51 | if __name__ == '__main__':
52 | main(sys.argv[1:])
53 |
--------------------------------------------------------------------------------
/apple/compile_entitlements.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/apple/compile_plist.gni")
6 |
7 | # Template to merge multiple .entitlements files performing variable
8 | # substitutions.
9 | #
10 | # Arguments
11 | #
12 | # entitlements_templates:
13 | # string array, paths to entitlements files which will be used for the
14 | # bundle.
15 | #
16 | # substitutions:
17 | # string array, 'key=value' pairs used to replace ${key} by value
18 | # when generating the output plist file.
19 | #
20 | # output_name:
21 | # string, name of the generated entitlements file.
22 | template("compile_entitlements") {
23 | assert(defined(invoker.entitlements_templates),
24 | "A list of template plist files must be specified for $target_name")
25 |
26 | compile_plist(target_name) {
27 | forward_variables_from(invoker,
28 | "*",
29 | [
30 | "entitlements_templates",
31 | "format",
32 | "plist_templates",
33 | ])
34 |
35 | plist_templates = invoker.entitlements_templates
36 |
37 | # Entitlements files are always encoded in xml1.
38 | format = "xml1"
39 |
40 | # Entitlements files use unsubstitued variables, so define substitutions
41 | # to leave those variables untouched.
42 | if (!defined(substitutions)) {
43 | substitutions = []
44 | }
45 |
46 | substitutions += [
47 | "AppIdentifierPrefix=\$(AppIdentifierPrefix)",
48 | "CFBundleIdentifier=\$(CFBundleIdentifier)",
49 | ]
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/config/mips.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # These are primarily relevant in current_cpu == "mips*" contexts, where
6 | # MIPS code is being compiled. But they can also be relevant in the
7 | # other contexts when the code will change its behavior based on the
8 | # cpu it wants to generate code for.
9 | if (current_cpu == "mipsel") {
10 | declare_args() {
11 | # MIPS arch variant. Possible values are:
12 | # "r1"
13 | # "r2"
14 | # "r6"
15 | mips_arch_variant = "r1"
16 |
17 | # MIPS DSP ASE revision. Possible values are:
18 | # 0: unavailable
19 | # 1: revision 1
20 | # 2: revision 2
21 | mips_dsp_rev = 0
22 |
23 | # MIPS SIMD Arch compilation flag.
24 | mips_use_msa = false
25 |
26 | # MIPS floating-point ABI. Possible values are:
27 | # "hard": sets the GCC -mhard-float option.
28 | # "soft": sets the GCC -msoft-float option.
29 | mips_float_abi = "hard"
30 |
31 | # MIPS32 floating-point register width. Possible values are:
32 | # "fp32": sets the GCC -mfp32 option.
33 | # "fp64": sets the GCC -mfp64 option.
34 | # "fpxx": sets the GCC -mfpxx option.
35 | mips_fpu_mode = "fp32"
36 | }
37 | } else if (current_cpu == "mips64el") {
38 | # MIPS arch variant. Possible values are:
39 | # "r2"
40 | # "r6"
41 | if (current_os == "android" || target_os == "android") {
42 | declare_args() {
43 | mips_arch_variant = "r6"
44 |
45 | # MIPS SIMD Arch compilation flag.
46 | mips_use_msa = true
47 | }
48 | } else {
49 | declare_args() {
50 | mips_arch_variant = "r2"
51 |
52 | # MIPS SIMD Arch compilation flag.
53 | mips_use_msa = false
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/config/ios/BUILD.gn:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/sysroot.gni")
6 | import("//build/toolchain/mac/ios_sdk.gni")
7 |
8 | # This is included by reference in the //build/config/compiler:runtime_library
9 | # config that is applied to all targets. It is here to separate out the logic
10 | # that is iOS-only. Please see that target for advice on what should go in
11 | # :runtime_library vs. :compiler.
12 | config("runtime_library") {
13 | common_flags = [
14 | "-isysroot",
15 | sysroot,
16 | "-stdlib=libc++",
17 | ]
18 |
19 | if (use_ios_simulator) {
20 | common_flags += [ "-mios-simulator-version-min=$ios_deployment_target" ]
21 | } else {
22 | common_flags += [ "-miphoneos-version-min=$ios_deployment_target" ]
23 | }
24 |
25 | asmflags = common_flags
26 | cflags = common_flags
27 | ldflags = common_flags
28 |
29 | # TODO(crbug.com/634373): Remove once Xcode's libc++ has LLVM r256325. Most
30 | # likely this means one Xcode 8 is released and required.
31 | #if (use_xcode_clang && get_path_info(ios_sdk_version, "name") != "10") {
32 | # common_cc_flags = [
33 | # "-isystem",
34 | # rebase_path("//third_party/llvm-build/Release+Asserts/include/c++/v1",
35 | # root_build_dir),
36 | # ]
37 | #
38 | # cflags_cc = common_cc_flags
39 | # cflags_objcc = common_cc_flags
40 | #}
41 | }
42 |
43 | config("ios_dynamic_flags") {
44 | ldflags = [ "-Wl,-ObjC" ] # Always load Objective-C categories and class.
45 | }
46 |
47 | config("xctest_config") {
48 | common_flags = [
49 | "-F",
50 | "$ios_sdk_platform_path/Developer/Library/Frameworks",
51 | ]
52 |
53 | cflags = common_flags
54 | ldflags = common_flags
55 |
56 | libs = [
57 | "Foundation.framework",
58 | "XCTest.framework",
59 | ]
60 | }
61 |
62 | group("xctest") {
63 | public_configs = [ ":xctest_config" ]
64 | }
65 |
--------------------------------------------------------------------------------
/mac/package_framework.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import argparse
6 | import errno
7 | import os
8 | import shutil
9 | import sys
10 |
11 | def Main():
12 | parser = argparse.ArgumentParser(description='Create Mac Framework symlinks')
13 | parser.add_argument('--framework', action='store', type=str, required=True)
14 | parser.add_argument('--version', action='store', type=str)
15 | parser.add_argument('--contents', action='store', type=str, nargs='+')
16 | parser.add_argument('--stamp', action='store', type=str, required=True)
17 | args = parser.parse_args()
18 |
19 | VERSIONS = 'Versions'
20 | CURRENT = 'Current'
21 |
22 | # Ensure the Foo.framework/Versions/A/ directory exists and create the
23 | # Foo.framework/Versions/Current symlink to it.
24 | if args.version:
25 | try:
26 | os.makedirs(os.path.join(args.framework, VERSIONS, args.version), 0o755)
27 | except OSError as e:
28 | if e.errno != errno.EEXIST:
29 | raise e
30 | _Relink(os.path.join(args.version),
31 | os.path.join(args.framework, VERSIONS, CURRENT))
32 |
33 | # Establish the top-level symlinks in the framework bundle. The dest of
34 | # the symlinks may not exist yet.
35 | if args.contents:
36 | for item in args.contents:
37 | _Relink(os.path.join(VERSIONS, CURRENT, item),
38 | os.path.join(args.framework, item))
39 |
40 | # Write out a stamp file.
41 | if args.stamp:
42 | with open(args.stamp, 'w') as f:
43 | f.write(str(args))
44 |
45 | return 0
46 |
47 |
48 | def _Relink(dest, link):
49 | """Creates a symlink to |dest| named |link|. If |link| already exists,
50 | it is overwritten."""
51 | try:
52 | os.remove(link)
53 | except OSError as e:
54 | if e.errno != errno.ENOENT:
55 | shutil.rmtree(link)
56 | os.symlink(dest, link)
57 |
58 |
59 | if __name__ == '__main__':
60 | sys.exit(Main())
61 |
--------------------------------------------------------------------------------
/toolchain/apple/filter_libtool.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | from __future__ import print_function
6 |
7 | import os
8 | import re
9 | import subprocess
10 | import sys
11 |
12 | # This script executes libool and filters out logspam lines like:
13 | # '/path/to/libtool: file: foo.o has no symbols'
14 |
15 | SUPPRESSED_PATTERNS = [
16 | re.compile(v) for v in [
17 | r'^.*libtool: (?:for architecture: \S* )?file: .* has no symbols$',
18 | # Xcode 11 spelling of the "empty archive" warning.
19 | # TODO(thakis): Remove once we require Xcode 12.
20 | r'^.*libtool: warning for library: .* the table of contents is empty ' \
21 | r'\(no object file members in the library define global symbols\)$',
22 | # Xcode 12 spelling of the "empty archive" warning.
23 | r'^warning: .*libtool: archive library: .* ' \
24 | r'the table of contents is empty ',
25 | r'\(no object file members in the library define global symbols\)$',
26 | r'^.*libtool: warning same member name \(\S*\) in output file used ' \
27 | r'for input files: \S* and: \S* \(due to use of basename, ' \
28 | r'truncation, blank padding or duplicate input files\)$',
29 | ]
30 | ]
31 |
32 |
33 | def ShouldSuppressLine(line):
34 | """Returns whether the line should be filtered out."""
35 | for pattern in SUPPRESSED_PATTERNS:
36 | if pattern.match(line):
37 | return True
38 | return False
39 |
40 |
41 | def Main(cmd_list):
42 | env = os.environ.copy()
43 | libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
44 | _, err = libtoolout.communicate()
45 | for line in err.decode('UTF-8').splitlines():
46 | if not ShouldSuppressLine(line):
47 | print(line, file=sys.stderr)
48 | return libtoolout.returncode
49 |
50 |
51 | if __name__ == '__main__':
52 | sys.exit(Main(sys.argv[1:]))
53 |
--------------------------------------------------------------------------------
/apple/write_pkg_info.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import argparse
6 | import os
7 | import plist_util
8 | import sys
9 |
10 | # This script creates a PkgInfo file for an OS X .app bundle's plist.
11 | # Usage: python write_pkg_info.py --plist Foo.app/Contents/Info.plist \
12 | # --output Foo.app/Contents/PkgInfo
13 |
14 |
15 | def Main():
16 | parser = argparse.ArgumentParser(
17 | description='A script to write PkgInfo files for .app bundles.')
18 | parser.add_argument('--plist',
19 | required=True,
20 | help='Path to the Info.plist for the .app.')
21 | parser.add_argument('--output',
22 | required=True,
23 | help='Path to the desired output file.')
24 | args = parser.parse_args()
25 |
26 | # Remove the output if it exists already.
27 | if os.path.exists(args.output):
28 | os.unlink(args.output)
29 |
30 | plist = plist_util.LoadPList(args.plist)
31 | package_type = plist['CFBundlePackageType']
32 | if package_type != 'APPL':
33 | raise ValueError('Expected CFBundlePackageType to be %s, got %s' % \
34 | ('APPL', package_type))
35 |
36 | # The format of PkgInfo is eight characters, representing the bundle type
37 | # and bundle signature, each four characters. If that is missing, four
38 | # '?' characters are used instead.
39 | signature_code = plist.get('CFBundleSignature', '????')
40 | if len(signature_code) != 4:
41 | raise ValueError('CFBundleSignature should be exactly four characters, ' +
42 | 'got %s' % signature_code)
43 |
44 | with open(args.output, 'w') as fp:
45 | fp.write('%s%s' % (package_type, signature_code))
46 | return 0
47 |
48 |
49 | if __name__ == '__main__':
50 | # TODO(https://crbug.com/941669): Temporary workaround until all scripts use
51 | # python3 by default.
52 | if sys.version_info[0] < 3:
53 | os.execvp('python3', ['python3'] + sys.argv)
54 | sys.exit(Main())
55 |
--------------------------------------------------------------------------------
/toolchain/win/link_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import re
4 | import subprocess
5 | import sys
6 | from toolchain import GetEnv
7 |
8 |
9 | # A regex matching an argument corresponding to the output filename passed to
10 | # link.exe.
11 | _LINK_EXE_OUT_ARG = re.compile('/OUT:(?P.+)$', re.IGNORECASE)
12 |
13 |
14 | def UseSeparateMspdbsrv(env, args):
15 | """Allows to use a unique instance of mspdbsrv.exe per linker instead of a
16 | shared one."""
17 | if len(args) < 1:
18 | raise Exception("Not enough arguments")
19 |
20 | if args[0] != 'link.exe':
21 | return
22 |
23 | # Use the output filename passed to the linker to generate an endpoint name
24 | # for mspdbsrv.exe.
25 | endpoint_name = None
26 | for arg in args:
27 | m = _LINK_EXE_OUT_ARG.match(arg)
28 | if m:
29 | endpoint_name = re.sub(r'\W+', '',
30 | '%s_%d' % (m.group('out'), os.getpid()))
31 | break
32 |
33 | if endpoint_name is None:
34 | return
35 |
36 | # Adds the appropriate environment variable. This will be read by link.exe
37 | # to know which instance of mspdbsrv.exe it should connect to (if it's
38 | # not set then the default endpoint is used).
39 | env['_MSPDBSRV_ENDPOINT_'] = endpoint_name
40 |
41 | def main(arch, use_separate_mspdbsrv, *args):
42 | """Filter diagnostic output from link that looks like:
43 | ' Creating library ui.dll.lib and object ui.dll.exp'
44 | This happens when there are exports from the dll or exe.
45 | """
46 | env = GetEnv(arch)
47 | if use_separate_mspdbsrv == 'True':
48 | UseSeparateMspdbsrv(env, args)
49 | link = subprocess.Popen([args[0].replace('/', '\\')] + list(args[1:]),
50 | shell=True,
51 | env=env,
52 | stdout=subprocess.PIPE,
53 | stderr=subprocess.STDOUT,
54 | universal_newlines=True)
55 | out, _ = link.communicate()
56 | for line in out.splitlines():
57 | if not line.startswith(' Creating library '):
58 | print(line)
59 | return link.returncode
60 |
61 | if __name__ == '__main__':
62 | sys.exit(main(*sys.argv[1:]))
63 |
--------------------------------------------------------------------------------
/apple/apple_info_plist.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/apple/compile_plist.gni")
6 |
7 | # The base template used to generate Info.plist files for iOS and Mac apps and
8 | # frameworks.
9 | #
10 | # Arguments
11 | #
12 | # plist_templates:
13 | # string array, paths to plist files which will be used for the bundle.
14 | #
15 | # executable_name:
16 | # string, name of the generated target used for the product
17 | # and executable name as specified in the output Info.plist.
18 | #
19 | # format:
20 | # string, the format to `plutil -convert` the plist to when
21 | # generating the output.
22 | #
23 | # extra_substitutions:
24 | # (optional) string array, 'key=value' pairs for extra fields which are
25 | # specified in a source Info.plist template.
26 | #
27 | # output_name:
28 | # (optional) string, name of the generated plist file, default to
29 | # "$target_gen_dir/$target_name.plist".
30 | template("apple_info_plist") {
31 | assert(defined(invoker.executable_name),
32 | "The executable_name must be specified for $target_name")
33 | executable_name = invoker.executable_name
34 |
35 | compile_plist(target_name) {
36 | forward_variables_from(invoker,
37 | [
38 | "plist_templates",
39 | "testonly",
40 | "deps",
41 | "visibility",
42 | "format",
43 | ])
44 |
45 | if (defined(invoker.output_name)) {
46 | output_name = invoker.output_name
47 | } else {
48 | output_name = "$target_gen_dir/$target_name.plist"
49 | }
50 |
51 | substitutions = [
52 | "EXECUTABLE_NAME=$executable_name",
53 | "GCC_VERSION=com.apple.compilers.llvm.clang.1_0",
54 | "PRODUCT_NAME=$executable_name",
55 | ]
56 | if (defined(invoker.extra_substitutions)) {
57 | substitutions += invoker.extra_substitutions
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/toolchain/toolchain.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # Toolchain-related configuration that may be needed outside the context of the
6 | # toolchain() rules themselves.
7 |
8 | declare_args() {
9 | # How many symbols to include in the build. This affects the performance of
10 | # the build since the symbols are large and dealing with them is slow.
11 | # 2 means regular build with symbols.
12 | # 1 means minimal symbols, usually enough for backtraces only.
13 | # 0 means no symbols.
14 | symbol_level = 2
15 | }
16 |
17 | # If it wasn't manually set, set to an appropriate default.
18 | assert(symbol_level >= 0 && symbol_level <= 2, "Invalid symbol_level")
19 |
20 | # Extension for shared library files (including leading dot).
21 | if (is_mac) {
22 | shlib_extension = ".dylib"
23 | } else if (is_posix) {
24 | shlib_extension = ".so"
25 | } else if (is_win) {
26 | shlib_extension = ".dll"
27 | } else {
28 | assert(false, "Platform not supported")
29 | }
30 |
31 | # Prefix for shared library files.
32 | if (is_posix) {
33 | shlib_prefix = "lib"
34 | } else {
35 | shlib_prefix = ""
36 | }
37 |
38 | # While other "tool"s in a toolchain are specific to the target of that
39 | # toolchain, the "stamp" and "copy" tools are really generic to the host;
40 | # but each toolchain must define them separately. GN doesn't allow a
41 | # template instantiation inside a toolchain definition, so some boilerplate
42 | # has to be repeated in each toolchain to define these two tools. These
43 | # four variables reduce the duplication in that boilerplate.
44 | stamp_description = "STAMP {{output}}"
45 | copy_description = "COPY {{source}} {{output}}"
46 | if (host_os == "win") {
47 | copy_path =
48 | rebase_path("//build/toolchain/win/recursive_mirror.py", root_build_dir)
49 |
50 | stamp_command = "cmd /c type nul > \"{{output}}\""
51 | copy_command = "$python_path $copy_path {{source}} {{output}}"
52 | } else {
53 | stamp_command = "touch {{output}}"
54 | copy_command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
55 | }
56 |
--------------------------------------------------------------------------------
/toolchain/gcc_ar_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2015 The Chromium Authors. All rights reserved.
3 | # Use of this source code is governed by a BSD-style license that can be
4 | # found in the LICENSE file.
5 |
6 | """Runs the 'ar' command after removing its output file first.
7 |
8 | This script is invoked like:
9 | python gcc_ar_wrapper.py --ar=$AR --output=$OUT $OP $INPUTS
10 | to do the equivalent of:
11 | rm -f $OUT && $AR $OP $OUT $INPUTS
12 | """
13 |
14 | import argparse
15 | import os
16 | import subprocess
17 | import sys
18 | import errno
19 |
20 | import wrapper_utils
21 |
22 |
23 | def main():
24 | parser = argparse.ArgumentParser(description=__doc__)
25 | parser.add_argument('--ar',
26 | required=True,
27 | help='The ar binary to run',
28 | metavar='PATH')
29 | parser.add_argument('--output',
30 | required=True,
31 | help='Output archive file',
32 | metavar='ARCHIVE')
33 | parser.add_argument('--plugin',
34 | help='Load plugin')
35 | parser.add_argument('--resource-whitelist',
36 | help='Merge all resource whitelists into a single file.',
37 | metavar='PATH')
38 | parser.add_argument('operation',
39 | help='Operation on the archive')
40 | parser.add_argument('inputs', nargs='+',
41 | help='Input files')
42 | args = parser.parse_args()
43 |
44 | if args.resource_whitelist:
45 | whitelist_candidates = wrapper_utils.ResolveRspLinks(args.inputs)
46 | wrapper_utils.CombineResourceWhitelists(
47 | whitelist_candidates, args.resource_whitelist)
48 |
49 | command = [args.ar, args.operation]
50 | if args.plugin is not None:
51 | command += ['--plugin', args.plugin]
52 | command.append(args.output)
53 | command += args.inputs
54 |
55 | # Remove the output file first.
56 | try:
57 | os.remove(args.output)
58 | except OSError as e:
59 | if e.errno != errno.ENOENT:
60 | raise
61 |
62 | # Now just run the ar command.
63 | return subprocess.call(wrapper_utils.CommandToRun(command))
64 |
65 |
66 | if __name__ == "__main__":
67 | sys.exit(main())
68 |
--------------------------------------------------------------------------------
/config/posix/BUILD.gn:
--------------------------------------------------------------------------------
1 | import("//build/config/sanitizers/sanitizers.gni")
2 | import("//build/toolchain/sysroot.gni")
3 |
4 | assert(is_posix)
5 |
6 | # This is included by reference in the //build/config/compiler config that
7 | # is applied to all targets. It is here to separate out the logic that is
8 | # Posix-only.
9 | config("compiler") {
10 | cflags = []
11 | ldflags = []
12 |
13 | if (is_freebsd && is_clang) {
14 | # GCC seems to include /usr/local/include in its default include dirs.
15 | cflags += [ "-isystem/usr/local/include" ]
16 | ldflags += [ "-B/usr/local/bin" ]
17 | }
18 | }
19 |
20 | # This is included by reference in the //build/config/compiler:runtime_library
21 | # config that is applied to all targets. It is here to separate out the logic
22 | # that is Posix-only. Please see that target for advice on what should go in
23 | # :runtime_library vs. :compiler.
24 | config("runtime_library") {
25 | if (!is_mac && sysroot != "") {
26 | # Pass the sysroot to all C compiler variants, the assembler, and linker.
27 | cflags = [ "--sysroot=" + rebase_path(sysroot, root_build_dir) ]
28 | asmflags = cflags
29 | ldflags = cflags
30 |
31 | # TODO: Need to get some linker flags out of the sysroot.
32 | }
33 | }
34 |
35 | # Settings for executables.
36 | config("executable_ldconfig") {
37 | # Find the path containing shared libraries for this toolchain
38 | # relative to the build directory. ${root_out_dir} will be a
39 | # subdirectory of ${root_build_dir} when cross compiling.
40 | rpath_link = rebase_path(root_out_dir, root_build_dir)
41 |
42 | ldflags = [
43 | # Want to pass "\$". GN will re-escape as required for ninja.
44 | "-Wl,-rpath=\$ORIGIN",
45 | "-Wl,-rpath-link=${rpath_link}",
46 |
47 | # Newer binutils don't set DT_RPATH unless you disable "new" dtags
48 | # and the new DT_RUNPATH doesn't work without --no-as-needed flag.
49 | "-Wl,--disable-new-dtags",
50 | ]
51 |
52 | if (current_cpu == "mipsel") {
53 | ldflags += [ "-pie" ]
54 | }
55 | }
56 |
57 | # This config ensures that targets do not refer to symbols unresolved at
58 | # compile time.
59 | # Disable this for DSOs that depend on symbols of the executables
60 | # that load them (e.g. Apache modules)
61 | config("no_undefined") {
62 | if (!using_sanitizer && !use_cfi_diag) {
63 | ldflags = [ "-Wl,-z,defs" ]
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/toolchain/posix/BUILD.gn:
--------------------------------------------------------------------------------
1 | import("//build/toolchain/gcc_toolchain.gni")
2 | import("//build/toolchain/posix/settings.gni")
3 |
4 | gcc_toolchain("clang_x86") {
5 | cc = clang_cc
6 | cxx = clang_cxx
7 | ld = cxx
8 |
9 | readelf = readelf
10 | ar = ar
11 | nm = nm
12 |
13 | toolchain_args = {
14 | current_cpu = "x86"
15 | current_os = target_os
16 | is_clang = true
17 | }
18 | }
19 |
20 | gcc_toolchain("x86") {
21 | cc = gcc_cc
22 | cxx = gcc_cxx
23 | ld = cxx
24 |
25 | readelf = readelf
26 | ar = ar
27 | nm = nm
28 |
29 | toolchain_args = {
30 | current_cpu = "x86"
31 | current_os = target_os
32 | is_clang = false
33 | }
34 | }
35 |
36 | gcc_toolchain("clang_x64") {
37 | cc = clang_cc
38 | cxx = clang_cxx
39 | ld = cxx
40 |
41 | readelf = readelf
42 | ar = ar
43 | nm = nm
44 |
45 | toolchain_args = {
46 | current_cpu = "x64"
47 | current_os = target_os
48 | is_clang = true
49 | }
50 | }
51 |
52 | gcc_toolchain("x64") {
53 | cc = gcc_cc
54 | cxx = gcc_cxx
55 | ld = cxx
56 |
57 | readelf = readelf
58 | ar = ar
59 | nm = nm
60 |
61 | toolchain_args = {
62 | current_cpu = "x64"
63 | current_os = target_os
64 | is_clang = false
65 | }
66 | }
67 |
68 | gcc_toolchain("clang_arm") {
69 | cc = clang_cc
70 | cxx = clang_cxx
71 | ld = cxx
72 |
73 | readelf = readelf
74 | ar = ar
75 | nm = nm
76 |
77 | toolchain_args = {
78 | current_cpu = "arm"
79 | current_os = target_os
80 | is_clang = true
81 | }
82 | }
83 |
84 | gcc_toolchain("arm") {
85 | cc = gcc_cc
86 | cxx = gcc_cxx
87 | ld = cxx
88 |
89 | readelf = readelf
90 | ar = ar
91 | nm = nm
92 |
93 | toolchain_args = {
94 | current_cpu = "arm"
95 | current_os = target_os
96 | is_clang = false
97 | }
98 | }
99 |
100 | gcc_toolchain("clang_arm64") {
101 | cc = clang_cc
102 | cxx = clang_cxx
103 | ld = cxx
104 |
105 | readelf = readelf
106 | ar = ar
107 | nm = nm
108 |
109 | toolchain_args = {
110 | current_cpu = "arm64"
111 | current_os = target_os
112 | is_clang = true
113 | }
114 | }
115 |
116 | gcc_toolchain("arm64") {
117 | cc = gcc_cc
118 | cxx = gcc_cxx
119 | ld = cxx
120 |
121 | readelf = readelf
122 | ar = ar
123 | nm = nm
124 |
125 | toolchain_args = {
126 | current_cpu = "arm64"
127 | current_os = target_os
128 | is_clang = false
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/toolchain/win/rc_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import subprocess
3 | import sys
4 | import os
5 | from toolchain import GetEnv
6 |
7 | msvc_deps_prefix = 'Note: including file: '
8 |
9 | def call(*popenargs, **kwargs):
10 | process = subprocess.Popen(stdout=subprocess.PIPE, universal_newlines=True,
11 | *popenargs, **kwargs)
12 | output, unused_err = process.communicate()
13 | return process.poll(), output
14 |
15 | def main(arch, source, output, rc_name, *args):
16 | """Output header dependencies and filter logo banner from invocations
17 | of rc.exe. Older versions of RC don't support the /nologo flag."""
18 | env = GetEnv(arch)
19 | args = list(args)
20 |
21 | output_dir = os.path.split(output)[0]
22 | source_name = os.path.split(source)[1]
23 |
24 | # Try fixing all those relative include directories.
25 | def fix_dirs(arg):
26 | if not arg.startswith('-I'):
27 | return arg
28 |
29 | return '/I{}'.format(os.path.relpath(arg[2:], output_dir))
30 |
31 | cl_args = list(map(fix_dirs, args))
32 |
33 | # This needs shell=True to search the path in env for the cl executable.
34 | retcode, out = call(["cl.exe", "/nologo", "/showIncludes", "/wd4005"] +
35 | cl_args + ["/P", os.path.relpath(source, output_dir)],
36 | env=env,
37 | stderr=subprocess.STDOUT,
38 | shell=True,
39 | # This is necessary so our .i file (generated by /P)
40 | # doesn't get written to the root build directory.
41 | cwd=output_dir)
42 | if retcode:
43 | print(out)
44 | return retcode
45 |
46 | # Now we need to fix the relative paths of our included files
47 | for line in out.splitlines():
48 | if not line or line.strip() == source_name:
49 | continue
50 |
51 | if not line.startswith(msvc_deps_prefix):
52 | print(line)
53 | continue
54 |
55 | filename = line[len(msvc_deps_prefix):].strip()
56 | filename = os.path.normpath(os.path.join(output_dir, filename))
57 |
58 | print('{}{}'.format(msvc_deps_prefix, filename))
59 |
60 | retcode, out = call([rc_name] + args + ["/fo" + output, source],
61 | shell=True, env=env, stderr=subprocess.STDOUT)
62 | for line in out.splitlines():
63 | if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and
64 | not line.startswith('Copyright (C) Microsoft Corporation') and
65 | line):
66 | print(line)
67 | return retcode
68 |
69 | if __name__ == '__main__':
70 | sys.exit(main(*sys.argv[1:]))
71 |
--------------------------------------------------------------------------------
/toolchain/compiler_version.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/toolchain.gni")
6 |
7 | # Bring all the windows toolchain definitions in.
8 | # Officially msc_ver etc. live here, but they're actually defined
9 | # in win/settings.gni.
10 | if (is_win) {
11 | import("//build/toolchain/win/settings.gni")
12 | }
13 |
14 | # Defines compiler versions for compilers used by multiple toolchains.
15 |
16 | # TODO(tim): Disable gcc_version on Windows?
17 | declare_args() {
18 | # Version of the GCC compiler.
19 | # Auto-detection is toolchain-specific and happens only if GCC is the active
20 | # compiler.
21 | # Format: MAJOR * 10000 + MINOR * 100 + PATCHLEVEL
22 | gcc_version = 0
23 |
24 | # Version of the Clang compiler.
25 | # Auto-detection is toolchain-specific and happens only if Clang is the
26 | # active compiler.
27 | # Format: MAJOR * 10000 + MINOR * 100 + PATCHLEVEL
28 | clang_version = 0
29 | }
30 |
31 | # If the user didn't specify the compiler version, attempt to autodetect it.
32 |
33 | if (gcc_version == 0 && !is_clang && !is_win) {
34 | if (is_android) {
35 | # sync with //build/toolchain/android/BUILD.gn
36 | import("//build/toolchain/android/settings.gni")
37 | _exe = "${android_tool_prefix}gcc"
38 | } else if (is_posix) {
39 | import("//build/toolchain/posix/settings.gni")
40 | _exe = gcc_cc
41 | } else {
42 | assert(false, "GCC isn't supported on this platform")
43 | }
44 | gcc_version = exec_script("posix/toolchain.py",
45 | [
46 | "get_gcc_version",
47 | _exe,
48 | ],
49 | "trim value")
50 | }
51 |
52 | if (clang_version == 0 && is_clang && !is_win) {
53 | if (is_android) {
54 | # sync with //build/toolchain/android/BUILD.gn
55 | import("//build/toolchain/clang.gni")
56 | _exe = "$clang_base_path/bin/clang"
57 | } else if (is_posix) {
58 | import("//build/toolchain/posix/settings.gni")
59 | _exe = clang_cc
60 | } else {
61 | assert(false, "GCC isn't supported on this platform")
62 | }
63 | clang_version = exec_script("posix/toolchain.py",
64 | [
65 | "get_clang_version",
66 | _exe,
67 | ],
68 | "trim value")
69 | } else if (clang_version == 0 && is_clang) {
70 | clang_version = win_clang_version
71 | }
72 |
--------------------------------------------------------------------------------
/config/precompiled_header.gni:
--------------------------------------------------------------------------------
1 | declare_args() {
2 | disable_precompiled_headers = false
3 | }
4 |
5 | # Define a config setting up a precompiled header.
6 | #
7 | # Precompiled headers are done on a per-target basis. If you have just a couple
8 | # of files, the time it takes to precompile (~2 seconds) can actually be longer
9 | # than the time saved. On a Z620, a 100 file target compiles about 2 seconds
10 | # faster with precompiled headers, with greater savings for larger targets.
11 | #
12 | # Recommend precompiled headers for targets with more than 50 .cc files.
13 | #
14 | # precompiled_header (required)
15 | # A string referring to the header file.
16 | #
17 | # precompiled_source (required)
18 | # GN path of a source file which will be compiled to a PCH.
19 | template("precompiled_header") {
20 | assert(defined(invoker.precompiled_header),
21 | "Need precompiled_header in $target_name.")
22 | assert(defined(invoker.precompiled_source),
23 | "Need precompiled_header in $target_name.")
24 |
25 | config(target_name) {
26 | if (!disable_precompiled_headers) {
27 | # This is a string rather than a file GN knows about. It has to match
28 | # exactly what's in the /FI flag below, and what might appear in the source
29 | # code in quotes for an #include directive.
30 | precompiled_header = invoker.precompiled_header
31 |
32 | # This is a file that GN will compile with the above header. It will be
33 | # implicitly added to the sources (potentially multiple times, with one
34 | # variant for each language used in the target).
35 |
36 | if (is_win) {
37 | precompiled_source = invoker.precompiled_source
38 |
39 | # Force include the header.
40 | cflags = [ "/FI$precompiled_header" ]
41 |
42 | # Disable warning for "this file was empty after preprocessing". This
43 | # error is generated only in C mode for ANSI compatibility. It conflicts
44 | # with precompiled headers since the source file that's "compiled" for
45 | # making the precompiled header is empty.
46 | #
47 | # This error doesn't happen every time. In VS2013, it seems if the .pch
48 | # file doesn't exist, no error will be generated (probably MS tested this
49 | # case but forgot the other one?). To reproduce this error, do a build,
50 | # then delete the precompile.c.obj file, then build again.
51 | cflags_c = [ "/wd4206" ]
52 | } else {
53 | # TODO(tim): Dirty hack to mark the variable as used.
54 | precompiled_source = invoker.precompiled_source
55 |
56 | precompiled_source = invoker.precompiled_header
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/toolchain/mac/BUILD.gn:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/mac/mac_sdk.gni")
6 | import("//build/toolchain/apple/toolchain.gni")
7 |
8 | # Specialisation of the apple_toolchain template to declare the toolchain
9 | # and its tools to build target for macOS platform.
10 | template("mac_toolchain") {
11 | assert(defined(invoker.toolchain_args),
12 | "Toolchains must declare toolchain_args")
13 |
14 | apple_toolchain(target_name) {
15 | forward_variables_from(invoker, "*", [ "toolchain_args" ])
16 |
17 | bin_path = mac_bin_path
18 |
19 | toolchain_args = {
20 | forward_variables_from(invoker.toolchain_args, "*")
21 | current_os = "mac"
22 |
23 | if (target_os == "ios") {
24 | # TODO(crbug.com/753445): the use_sanitizer_coverage arg is currently
25 | # not supported by the Chromium mac_clang_x64 toolchain on iOS
26 | # distribution.
27 | use_sanitizer_coverage = false
28 |
29 | # Do not use Xcode version of clang when building macOS tools for the
30 | # host even if this is the version used to build for the iOS target.
31 | use_xcode_clang = false
32 | }
33 | }
34 | }
35 | }
36 |
37 | mac_toolchain("clang_arm") {
38 | toolchain_args = {
39 | current_cpu = "arm"
40 | }
41 | }
42 |
43 | mac_toolchain("clang_arm64") {
44 | toolchain_args = {
45 | current_cpu = "arm64"
46 | }
47 | }
48 |
49 | mac_toolchain("clang_x64") {
50 | toolchain_args = {
51 | current_cpu = "x64"
52 | }
53 | }
54 |
55 | mac_toolchain("clang_x86") {
56 | toolchain_args = {
57 | current_cpu = "x86"
58 | }
59 | }
60 |
61 | mac_toolchain("clang_x86_v8_arm") {
62 | toolchain_args = {
63 | current_cpu = "x86"
64 |
65 | if (defined(v8_current_cpu)) {
66 | v8_current_cpu = "arm"
67 | }
68 | }
69 | }
70 |
71 | mac_toolchain("clang_x86_v8_mipsel") {
72 | toolchain_args = {
73 | current_cpu = "x86"
74 |
75 | if (defined(v8_current_cpu)) {
76 | v8_current_cpu = "mipsel"
77 | }
78 | }
79 | }
80 |
81 | mac_toolchain("clang_x64_v8_arm64") {
82 | toolchain_args = {
83 | current_cpu = "x64"
84 |
85 | if (defined(v8_current_cpu)) {
86 | v8_current_cpu = "arm64"
87 | }
88 | }
89 | }
90 |
91 | mac_toolchain("clang_x64_v8_mips64el") {
92 | toolchain_args = {
93 | current_cpu = "x64"
94 |
95 | if (defined(v8_current_cpu)) {
96 | v8_current_cpu = "mips64el"
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/toolchain/clang_static_analyzer_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2017 The Chromium Authors. All rights reserved.
3 | # Use of this source code is governed by a BSD-style license that can be
4 | # found in the LICENSE file.
5 |
6 | """Adds an analysis build step to invocations of the Clang C/C++ compiler.
7 |
8 | Usage: clang_static_analyzer_wrapper.py [args...]
9 | """
10 |
11 | import argparse
12 | import fnmatch
13 | import itertools
14 | import os
15 | import sys
16 | import wrapper_utils
17 |
18 | # Flags used to enable analysis for Clang invocations.
19 | analyzer_enable_flags = [
20 | '--analyze',
21 | ]
22 |
23 | # Flags used to configure the analyzer's behavior.
24 | analyzer_option_flags = [
25 | '-fdiagnostics-show-option',
26 | '-analyzer-checker=cplusplus',
27 | '-analyzer-opt-analyze-nested-blocks',
28 | '-analyzer-eagerly-assume',
29 | '-analyzer-output=text',
30 | '-analyzer-config',
31 | 'suppress-c++-stdlib=true',
32 |
33 | # List of checkers to execute.
34 | # The full list of checkers can be found at
35 | # https://clang-analyzer.llvm.org/available_checks.html.
36 | '-analyzer-checker=core',
37 | '-analyzer-checker=unix',
38 | '-analyzer-checker=deadcode',
39 | ]
40 |
41 |
42 | # Prepends every element of a list |args| with |token|.
43 | # e.g. ['-analyzer-foo', '-analyzer-bar'] => ['-Xanalyzer', '-analyzer-foo',
44 | # '-Xanalyzer', '-analyzer-bar']
45 | def interleave_args(args, token):
46 | return list(sum(zip([token] * len(args), args), ()))
47 |
48 |
49 | def main():
50 | parser = argparse.ArgumentParser()
51 | parser.add_argument('--mode',
52 | choices=['clang', 'cl'],
53 | required=True,
54 | help='Specifies the compiler argument convention to use.')
55 | parser.add_argument('args', nargs=argparse.REMAINDER)
56 | parsed_args = parser.parse_args()
57 |
58 | prefix = '-Xclang' if parsed_args.mode == 'cl' else '-Xanalyzer'
59 | cmd = parsed_args.args + analyzer_enable_flags + \
60 | interleave_args(analyzer_option_flags, prefix)
61 | returncode, stderr = wrapper_utils.CaptureCommandStderr(
62 | wrapper_utils.CommandToRun(cmd))
63 | sys.stderr.write(stderr)
64 | if returncode != 0:
65 | sys.stderr.write(
66 | """WARNING! The Clang static analyzer exited with error code %d.
67 | Please share the error details in crbug.com/695243 if this looks like
68 | a new regression.\n""" % (returncode))
69 |
70 | returncode, stderr = wrapper_utils.CaptureCommandStderr(
71 | wrapper_utils.CommandToRun(parsed_args.args))
72 | sys.stderr.write(stderr)
73 |
74 | return returncode
75 |
76 | if __name__ == '__main__':
77 | sys.exit(main())
78 |
--------------------------------------------------------------------------------
/config/compiler.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/config/sanitizers/sanitizers.gni")
6 | import("//build/config/arm.gni")
7 |
8 | declare_args() {
9 | # Compile in such a way as to enable profiling of the generated code. For
10 | # example, don't omit the frame pointer and leave in symbols.
11 | enable_profiling = false
12 |
13 | # Enable Link Time Optimization in optimized builds (output programs run
14 | # faster, but linking is up to 5-20x slower).
15 | enable_lto = is_official_build && is_win && !is_clang
16 |
17 | # Enable some optimizations that don't interfere with debugging.
18 | optimize_debug = false
19 |
20 | # use_debug_fission: whether to use split DWARF debug info
21 | # files. This can reduce link time significantly, but is incompatible
22 | # with some utilities such as icecc and ccache. Requires gold and
23 | # gcc >= 4.8 or clang.
24 | # http://gcc.gnu.org/wiki/DebugFission
25 | #
26 | # This is a placeholder value indicating that the code below should set
27 | # the default. This is necessary to delay the evaluation of the default
28 | # value expression until after its input values such as use_gold have
29 | # been set, e.g. by a toolchain_args() block.
30 | use_debug_fission = false
31 |
32 | # Whether to use the gold linker from binutils instead of lld or bfd.
33 | use_gold = false
34 |
35 | # Tell VS to create a PDB that references information in .obj files rather
36 | # than copying it all. This should improve linker performance. mspdbcmf.exe
37 | # can be used to convert a fastlink pdb to a normal one.
38 | is_win_fastlink = false
39 | }
40 |
41 | # Whether to emit frame pointers by default.
42 | if (is_mac || is_ios) {
43 | enable_frame_pointers = true
44 | } else if (is_win) {
45 | # 64-bit Windows ABI doesn't support frame pointers.
46 | if (target_cpu == "x64") {
47 | enable_frame_pointers = false
48 | } else {
49 | enable_frame_pointers = true
50 | }
51 | } else {
52 | # Explicitly ask for frame pointers, otherwise:
53 | # * Stacks may be missing for sanitizer and profiling builds.
54 | # * Debug tcmalloc can crash (crbug.com/636489).
55 | # * Stacks may be missing for arm64 crash dumps (crbug.com/391706).
56 | enable_frame_pointers =
57 | using_sanitizer || enable_profiling || is_debug || current_cpu == "arm64"
58 | }
59 |
60 | # Unwinding with frame pointers requires that frame pointers are enabled by
61 | # default for most translation units, and that the architecture isn't thumb, as
62 | # frame pointers are not correctly emitted for thumb.
63 | if (enable_frame_pointers && !(current_cpu == "arm" && arm_use_thumb)) {
64 | can_unwind_with_frame_pointers = true
65 | } else {
66 | can_unwind_with_frame_pointers = false
67 | }
68 |
--------------------------------------------------------------------------------
/apple/compile_plist.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2021 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # Template to merge multiple plist files and perform variable substitutions.
6 | #
7 | # Arguments
8 | #
9 | # plist_templates:
10 | # string array, paths to plist files which will be used for the bundle.
11 | #
12 | # format:
13 | # string, the format to `plutil -convert` the plist to when
14 | # generating the output.
15 | #
16 | # substitutions:
17 | # string array, 'key=value' pairs used to replace ${key} by value
18 | # when generating the output plist file.
19 | #
20 | # output_name:
21 | # string, name of the generated plist file.
22 | template("compile_plist") {
23 | assert(defined(invoker.plist_templates),
24 | "A list of template plist files must be specified for $target_name")
25 | assert(defined(invoker.format),
26 | "The plist format must be specified for $target_name")
27 | assert(defined(invoker.substitutions),
28 | "A list of key=value pairs must be specified for $target_name")
29 | assert(defined(invoker.output_name),
30 | "The name of the output file must be specified for $target_name")
31 |
32 | _output_name = invoker.output_name
33 | _merged_name = get_path_info(_output_name, "dir") + "/" +
34 | get_path_info(_output_name, "name") + "_merged." +
35 | get_path_info(_output_name, "extension")
36 |
37 | _merge_target = target_name + "_merge"
38 |
39 | action(_merge_target) {
40 | forward_variables_from(invoker,
41 | [
42 | "deps",
43 | "testonly",
44 | ])
45 |
46 | script = "//build/apple/plist_util.py"
47 | sources = invoker.plist_templates
48 | outputs = [ _merged_name ]
49 | args = [
50 | "merge",
51 | "-f=" + invoker.format,
52 | "-o=" + rebase_path(_merged_name, root_build_dir),
53 | ] + rebase_path(invoker.plist_templates, root_build_dir)
54 | }
55 |
56 | action(target_name) {
57 | forward_variables_from(invoker,
58 | [
59 | "testonly",
60 | "visibility",
61 | ])
62 | script = "//build/apple/plist_util.py"
63 | sources = [ _merged_name ]
64 | outputs = [ _output_name ]
65 | args = [
66 | "substitute",
67 | "-f=" + invoker.format,
68 | "-o=" + rebase_path(_output_name, root_build_dir),
69 | "-t=" + rebase_path(_merged_name, root_build_dir),
70 | ]
71 | foreach(_substitution, invoker.substitutions) {
72 | args += [ "-s=$_substitution" ]
73 | }
74 | deps = [ ":$_merge_target" ]
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/toolchain/gcc_link_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2015 The Chromium Authors. All rights reserved.
3 | # Use of this source code is governed by a BSD-style license that can be
4 | # found in the LICENSE file.
5 |
6 | """Runs a linking command and optionally a strip command.
7 |
8 | This script exists to avoid using complex shell commands in
9 | gcc_toolchain.gni's tool("link"), in case the host running the compiler
10 | does not have a POSIX-like shell (e.g. Windows).
11 | """
12 |
13 | import argparse
14 | import os
15 | import subprocess
16 | import sys
17 |
18 | import wrapper_utils
19 |
20 |
21 | # When running on a Windows host and using a toolchain whose tools are
22 | # actually wrapper scripts (i.e. .bat files on Windows) rather than binary
23 | # executables, the "command" to run has to be prefixed with this magic.
24 | # The GN toolchain definitions take care of that for when GN/Ninja is
25 | # running the tool directly. When that command is passed in to this
26 | # script, it appears as a unitary string but needs to be split up so that
27 | # just 'cmd' is the actual command given to Python's subprocess module.
28 | BAT_PREFIX = 'cmd /c call '
29 |
30 | def CommandToRun(command):
31 | if command[0].startswith(BAT_PREFIX):
32 | command = command[0].split(None, 3) + command[1:]
33 | return command
34 |
35 |
36 | def main():
37 | parser = argparse.ArgumentParser(description=__doc__)
38 | parser.add_argument('--strip',
39 | help='The strip binary to run',
40 | metavar='PATH')
41 | parser.add_argument('--unstripped-file',
42 | help='Executable file produced by linking command',
43 | metavar='FILE')
44 | parser.add_argument('--map-file',
45 | help=('Use --Wl,-Map to generate a map file. Will be '
46 | 'gzipped if extension ends with .gz'),
47 | metavar='FILE')
48 | parser.add_argument('--output',
49 | required=True,
50 | help='Final output executable file',
51 | metavar='FILE')
52 | parser.add_argument('command', nargs='+',
53 | help='Linking command')
54 | args = parser.parse_args()
55 |
56 | # Work-around for gold being slow-by-default. http://crbug.com/632230
57 | fast_env = dict(os.environ)
58 | fast_env['LC_ALL'] = 'C'
59 | result = wrapper_utils.RunLinkWithOptionalMapFile(args.command, env=fast_env,
60 | map_file=args.map_file)
61 | if result != 0:
62 | return result
63 |
64 | # Finally, strip the linked executable (if desired).
65 | if args.strip:
66 | result = subprocess.call(CommandToRun([
67 | args.strip, '--strip-unneeded', '-o', args.output, args.unstripped_file
68 | ]))
69 |
70 | return result
71 |
72 |
73 | if __name__ == "__main__":
74 | sys.exit(main())
75 |
--------------------------------------------------------------------------------
/toolchain/win/message_compiler.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | assert(is_win, "This only runs on Windows.")
6 |
7 | # Runs mc.exe over a list of sources. The outputs (a header and rc file) are
8 | # placed in the target gen dir, and compiled.
9 | #
10 | # sources
11 | # List of message files to process.
12 | #
13 | # user_mode_logging (optional bool)
14 | # Generates user-mode logging code. Defaults to false (no logging code).
15 | #
16 | # compile_generated_code (optional, deafults = true)
17 | # If unset or true, the generated code will be compiled and linked into
18 | # targets that depend on it. If set to false, the .h and .rc files will only
19 | # be generated.
20 | #
21 | # deps, public_deps, visibility
22 | # Normal meaning.
23 | template("message_compiler") {
24 | if (defined(invoker.compile_generated_code) &&
25 | !invoker.compile_generated_code) {
26 | compile_generated_code = false
27 | action_name = target_name
28 | } else {
29 | compile_generated_code = true
30 | action_name = "${target_name}_mc"
31 | source_set_name = target_name
32 | }
33 |
34 | action_foreach(action_name) {
35 | if (compile_generated_code) {
36 | visibility = [ ":$source_set_name" ]
37 | } else {
38 | forward_variables_from(invoker, [ "visibility" ])
39 | }
40 |
41 | script = "//build/toolchain/win/message_compiler.py"
42 |
43 | outputs = [
44 | "$target_gen_dir/{{source_name_part}}.h",
45 | "$target_gen_dir/{{source_name_part}}.rc",
46 | ]
47 |
48 | args = [
49 | # The first argument is the environment file saved to the build
50 | # directory. This is required because the Windows toolchain setup saves
51 | # the VC paths and such so that running "mc.exe" will work with the
52 | # configured toolchain. This file is in the root build dir.
53 | "environment.$current_cpu",
54 |
55 | # Where to put the header.
56 | "-h",
57 | rebase_path(target_gen_dir, root_build_dir),
58 |
59 | # Where to put the .rc file.
60 | "-r",
61 | rebase_path(target_gen_dir, root_build_dir),
62 |
63 | # Input is Unicode.
64 | "-u",
65 | ]
66 | if (defined(invoker.user_mode_logging) && invoker.user_mode_logging) {
67 | args += [ "-um" ]
68 | }
69 | args += [ "{{source}}" ]
70 |
71 | forward_variables_from(invoker,
72 | [
73 | "deps",
74 | "public_deps",
75 | "sources",
76 | ])
77 | }
78 |
79 | if (compile_generated_code) {
80 | # Compile the generated rc file.
81 | source_set(source_set_name) {
82 | forward_variables_from(invoker, [ "visibility" ])
83 | sources = get_target_outputs(":$action_name")
84 | deps = [
85 | ":$action_name",
86 | ]
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/toolchain/win/midl.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | assert(is_win)
6 |
7 | import("//build/toolchain/win/settings.gni")
8 |
9 | # This template defines a rule to invoke the MS IDL compiler. The generated
10 | # source code will be compiled and linked into targets that depend on this.
11 | #
12 | # Parameters
13 | #
14 | # sources
15 | # List of .idl file to process.
16 | #
17 | # out_dir (optional)
18 | # Directory to write the generated files to. Defaults to target_gen_dir.
19 | #
20 | # deps (optional)
21 | # visibility (optional)
22 |
23 | template("midl") {
24 | action_name = "${target_name}_idl_action"
25 | source_set_name = target_name
26 |
27 | assert(defined(invoker.sources), "Source must be defined for $target_name")
28 |
29 | if (defined(invoker.out_dir)) {
30 | out_dir = invoker.out_dir
31 | } else {
32 | out_dir = target_gen_dir
33 | }
34 |
35 | header_file = "{{source_name_part}}.h"
36 | dlldata_file = "{{source_name_part}}.dlldata.c"
37 | interface_identifier_file = "{{source_name_part}}_i.c"
38 | proxy_file = "{{source_name_part}}_p.c"
39 | type_library_file = "{{source_name_part}}.tlb"
40 |
41 | action_foreach(action_name) {
42 | visibility = [ ":$source_set_name" ]
43 |
44 | script = "//build/toolchain/win/midl_wrapper.py"
45 |
46 | sources = invoker.sources
47 |
48 | # Note that .tlb is not included in the outputs as it is not always
49 | # generated depending on the content of the input idl file.
50 | outputs = [
51 | "$out_dir/$header_file",
52 | "$out_dir/$dlldata_file",
53 | "$out_dir/$interface_identifier_file",
54 | "$out_dir/$proxy_file",
55 | ]
56 |
57 | if (current_cpu == "x86") {
58 | win_tool_arch = x86_environment_path
59 | idl_target_platform = "win32"
60 | } else if (current_cpu == "x64") {
61 | win_tool_arch = x64_environment_path
62 | idl_target_platform = "x64"
63 | } else {
64 | assert(false, "Need environment for this arch")
65 | }
66 |
67 | args = [
68 | win_tool_arch,
69 | rebase_path(out_dir, root_build_dir),
70 | type_library_file,
71 | header_file,
72 | dlldata_file,
73 | interface_identifier_file,
74 | proxy_file,
75 | "{{source}}",
76 | "/char",
77 | "signed",
78 | "/env",
79 | idl_target_platform,
80 | "/Oicf",
81 | ]
82 |
83 | forward_variables_from(invoker, [ "deps" ])
84 | }
85 |
86 | source_set(target_name) {
87 | forward_variables_from(invoker, [ "visibility" ])
88 |
89 | # We only compile the IID files from the IDL tool rather than all outputs.
90 | sources = process_file_template(invoker.sources,
91 | [ "$out_dir/$interface_identifier_file" ])
92 |
93 | public_deps = [
94 | ":$action_name",
95 | ]
96 |
97 | configs += [ "//build/config/win:midl_warnings" ]
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/config/libc++/settings.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2017 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/config/sanitizers/sanitizers.gni")
6 | import("//build/toolchain/mac/settings.gni")
7 |
8 | declare_args() {
9 | # Use in-tree libc++ (buildtools/third_party/libc++ and
10 | # buildtools/third_party/libc++abi) instead of the system C++ library for C++
11 | # standard library support.
12 | # Don't check in changes that set this to false for more platforms; doing so
13 | # is not supported.
14 | use_custom_libcxx = is_fuchsia || is_android || is_mac ||
15 | (is_ios && !use_xcode_clang) || (is_win && is_clang) || is_linux
16 |
17 | # Use libc++ instead of stdlibc++ when using the host_cpu toolchain, even if
18 | # use_custom_libcxx is false. This is useful for cross-compiles where a custom
19 | # toolchain for the target_cpu has been set as the default toolchain, but
20 | # use_custom_libcxx should still be true when building for the host. The
21 | # expected usage is to set use_custom_libcxx=false and
22 | # use_custom_libcxx_for_host=true in the passed in buildargs.
23 | use_custom_libcxx_for_host = false
24 |
25 | # Builds libcxx Natvis into the symbols for type visualization.
26 | # Set to false to workaround http://crbug.com/966676 and
27 | # http://crbug.com/966687.
28 | libcxx_natvis_include = true
29 | }
30 |
31 | use_custom_libcxx =
32 | use_custom_libcxx || (use_custom_libcxx_for_host && !is_a_target_toolchain)
33 |
34 | declare_args() {
35 | # WARNING: Setting this to a non-default value is highly discouraged.
36 | # If true, libc++ will be built as a shared library; otherwise libc++ will be
37 | # linked statically. Setting this to something other than the default is
38 | # unsupported and can be broken by libc++ rolls. Note that if this is set to
39 | # true, you must also set libcxx_abi_unstable=false, which is bad for
40 | # performance and memory use.
41 | libcxx_is_shared = use_custom_libcxx
42 | }
43 |
44 | # libc++abi needs to be exported from executables to be picked up by shared
45 | # libraries on certain instrumented builds.
46 | export_libcxxabi_from_executables =
47 | use_custom_libcxx && !is_ios && !is_win && (is_asan || is_ubsan_vptr)
48 |
49 | # On Android, many shared libraries get loaded from the context of a JRE. In
50 | # this case, there's no "main executable" to export libc++abi from. We could
51 | # export libc++abi from each "toplevel" shared library instead, but that would
52 | # require adding an explicit dependency for each one, and might introduce
53 | # subtle, hard-to-fix problems down the line if the dependency is missing.
54 | #
55 | # export_libcxxabi_from_executables was added to avoid having an RPATH set in
56 | # static sanitizer builds just for executables to find libc++. But on Android,
57 | # the Bionic dynamic loader doesn't even look at RPATH; instead, LD_LIBRARY_PATH
58 | # is set for tests. Because of this, we make libc++ a shared library on android
59 | # since it should get loaded properly.
60 | if (is_android && export_libcxxabi_from_executables) {
61 | export_libcxxabi_from_executables = false
62 | libcxx_is_shared = true
63 | }
64 |
65 | libcxx_prefix = "//buildtools/third_party/libc++/trunk"
66 | libcxxabi_prefix = "//buildtools/third_party/libc++abi/trunk"
67 |
--------------------------------------------------------------------------------
/.github/workflows/windows.yml:
--------------------------------------------------------------------------------
1 | name: Windows
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - master
7 | - develop
8 | - feature/**
9 | push:
10 | branches:
11 | - master
12 | - develop
13 | - feature/**
14 | workflow_dispatch:
15 | release:
16 | types: published
17 |
18 | env:
19 | NINJA_BASE_URL: https://github.com/ninja-build/ninja/releases/download/
20 | GN_BASE_URL: https://github.com/timniederhausen/gn/releases/download/2021.03/
21 |
22 | jobs:
23 | windows:
24 | strategy:
25 | fail-fast: false
26 | matrix:
27 | include:
28 | # 2019
29 | - slug: windows-2019 debug
30 | gen_args: 'is_official_build = false'
31 | os: windows-2019
32 | ninja_release_name: v1.7.2/ninja-win.zip
33 | gn_release_name: gn-win-amd64.zip
34 |
35 | - slug: windows-2019 official
36 | gen_args: 'is_official_build = true'
37 | os: windows-2019
38 | ninja_release_name: v1.7.2/ninja-win.zip
39 | gn_release_name: gn-win-amd64.zip
40 |
41 | # 2022
42 | - slug: windows-2022 debug
43 | gen_args: 'is_official_build = false'
44 | os: windows-2022
45 | ninja_release_name: v1.7.2/ninja-win.zip
46 | gn_release_name: gn-win-amd64.zip
47 |
48 | - slug: windows-2022 official
49 | gen_args: 'is_official_build = true'
50 | os: windows-2022
51 | ninja_release_name: v1.7.2/ninja-win.zip
52 | gn_release_name: gn-win-amd64.zip
53 |
54 | runs-on: ${{ matrix.os }}
55 |
56 | steps:
57 | - uses: actions/checkout@v4
58 | with:
59 | # we need all everything for `git describe` to work correctly
60 | fetch-depth: 0
61 |
62 | - name: Install recent Ninja
63 | run: |
64 | Invoke-WebRequest -OutFile ninja.zip -Uri "${{ env.NINJA_BASE_URL }}${{ matrix.ninja_release_name }}"
65 | python -c 'import sys,zipfile;zipfile.ZipFile(sys.argv[1]).extractall()' ninja.zip
66 |
67 | - name: Install GN
68 | run: |
69 | Invoke-WebRequest -OutFile gn.zip -Uri "${{ env.GN_BASE_URL }}${{ matrix.gn_release_name }}"
70 | python -c 'import sys,zipfile;zipfile.ZipFile(sys.argv[1]).extractall()' gn.zip
71 |
72 | # Run gn_helpers unittests first - this should fail if we have an unsupported Python version
73 | # Only support Python3+ for now, otherwise we have to ship the mocking lib
74 | - name: Test gn_helpers
75 | run: |
76 | python3 gn_helpers_unittest.py
77 |
78 | # Setup test project for our //build
79 | - name: Setup test project
80 | run: |
81 | git clone --branch=testsrc --depth=1 https://github.com/timniederhausen/gn-build.git testsrc
82 | mkdir testsrc/build
83 | mv *.py testsrc/build/
84 | mv config testsrc/build/
85 | mv toolchain testsrc/build/
86 |
87 | # Try to generate ninja files with different python versions
88 | - name: gen with python3
89 | run: |
90 | .\gn.exe gen out --args='${{ matrix.gen_args }}' --root=testsrc
91 |
92 | # Try to build the test project
93 | - name: Build
94 | run: |
95 | cat out/args.gn
96 | .\ninja.exe -C out
97 | cd out && ./hello
98 |
--------------------------------------------------------------------------------
/config/arm.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # These are primarily relevant in current_cpu == "arm" contexts, where
6 | # ARM code is being compiled. But they can also be relevant in the
7 | # other contexts when the code will change its behavior based on the
8 | # cpu it wants to generate code for.
9 | if (current_cpu == "arm") {
10 | declare_args() {
11 | # Version of the ARM processor when compiling on ARM. Ignored on non-ARM
12 | # platforms.
13 | arm_version = 7
14 |
15 | # The ARM architecture. This will be a string like "armv6" or "armv7-a".
16 | # An empty string means to use the default for the arm_version.
17 | arm_arch = ""
18 |
19 | # The ARM floating point hardware. This will be a string like "neon" or
20 | # "vfpv3". An empty string means to use the default for the arm_version.
21 | arm_fpu = ""
22 |
23 | # The ARM floating point mode. This is either the string "hard", "soft", or
24 | # "softfp". An empty string means to use the default one for the
25 | # arm_version.
26 | arm_float_abi = ""
27 |
28 | # The ARM variant-specific tuning mode. This will be a string like "armv6"
29 | # or "cortex-a15". An empty string means to use the default for the
30 | # arm_version.
31 | arm_tune = ""
32 |
33 | # Whether to use the neon FPU instruction set or not.
34 | arm_use_neon = true
35 |
36 | # Whether to enable optional NEON code paths.
37 | arm_optionally_use_neon = false
38 |
39 | # Thumb is a reduced instruction set available on some ARM processors that
40 | # has increased code density.
41 | arm_use_thumb = true
42 | }
43 |
44 | assert(arm_float_abi == "" || arm_float_abi == "hard" ||
45 | arm_float_abi == "soft" || arm_float_abi == "softfp")
46 |
47 | if (arm_version == 6) {
48 | if (arm_arch == "") {
49 | arm_arch = "armv6"
50 | }
51 | if (arm_tune != "") {
52 | arm_tune = ""
53 | }
54 | if (arm_float_abi == "") {
55 | arm_float_abi = "softfp"
56 | }
57 | if (arm_fpu == "") {
58 | arm_fpu = "vfp"
59 | }
60 | arm_use_thumb = false
61 | arm_use_neon = false
62 | } else if (arm_version == 7) {
63 | if (arm_arch == "") {
64 | arm_arch = "armv7-a"
65 | }
66 | if (arm_tune == "") {
67 | arm_tune = "generic-armv7-a"
68 | }
69 |
70 | if (arm_float_abi == "") {
71 | if (current_os == "android" || target_os == "android") {
72 | arm_float_abi = "softfp"
73 | } else {
74 | arm_float_abi = "hard"
75 | }
76 | }
77 |
78 | if (arm_fpu == "") {
79 | if (arm_use_neon) {
80 | arm_fpu = "neon"
81 | } else {
82 | arm_fpu = "vfpv3-d16"
83 | }
84 | }
85 | } else if (arm_version == 8) {
86 | if (arm_arch == "") {
87 | arm_arch = "armv8-a"
88 | }
89 | if (arm_tune == "") {
90 | arm_tune = "generic-armv8-a"
91 | }
92 |
93 | if (arm_float_abi == "") {
94 | if (current_os == "android" || target_os == "android") {
95 | arm_float_abi = "softfp"
96 | } else {
97 | arm_float_abi = "hard"
98 | }
99 | }
100 |
101 | if (arm_fpu == "") {
102 | if (arm_use_neon) {
103 | arm_fpu = "neon"
104 | } else {
105 | arm_fpu = "vfpv3-d16"
106 | }
107 | }
108 | }
109 | } else if (current_cpu == "arm64") {
110 | # arm64 supports only "hard".
111 | arm_float_abi = "hard"
112 | arm_use_neon = true
113 | }
114 |
--------------------------------------------------------------------------------
/toolchain/mac/find_sdk.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 | # Use of this source code is governed by a BSD-style license that can be
4 | # found in the LICENSE file.
5 | r"""Prints the lowest locally available SDK version greater than or equal to a
6 | given minimum sdk version to standard output.
7 |
8 | If --print_sdk_path is passed, then the script will also print the SDK path.
9 | If --print_bin_path is passed, then the script will also print the path to the
10 | toolchain bin dir.
11 |
12 | Usage:
13 | python find_sdk.py \
14 | [--print_sdk_path] \
15 | [--print_bin_path] \
16 | 10.6 # Ignores SDKs < 10.6
17 |
18 | Sample Output:
19 | /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk
20 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/
21 | 10.14
22 | """
23 |
24 | from __future__ import print_function
25 |
26 | import os
27 | import re
28 | import subprocess
29 | import sys
30 |
31 | from optparse import OptionParser
32 |
33 |
34 | class SdkError(Exception):
35 | def __init__(self, value):
36 | self.value = value
37 | def __str__(self):
38 | return repr(self.value)
39 |
40 |
41 | def parse_version(version_str):
42 | """'10.6' => [10, 6]"""
43 | return [int(s) for s in re.findall(r'(\d+)', version_str)]
44 |
45 |
46 | def main():
47 | parser = OptionParser()
48 | parser.add_option("--print_sdk_path",
49 | action="store_true", dest="print_sdk_path", default=False,
50 | help="Additionally print the path the SDK (appears first).")
51 | parser.add_option("--print_bin_path",
52 | action="store_true", dest="print_bin_path", default=False,
53 | help="Additionally print the path the toolchain bin dir.")
54 | options, args = parser.parse_args()
55 | if len(args) != 1:
56 | parser.error('Please specify a minimum SDK version')
57 | min_sdk_version = args[0]
58 |
59 |
60 | job = subprocess.Popen(['xcode-select', '-print-path'],
61 | stdout=subprocess.PIPE,
62 | stderr=subprocess.STDOUT)
63 | out, err = job.communicate()
64 | if job.returncode != 0:
65 | print(out, file=sys.stderr)
66 | print(err, file=sys.stderr)
67 | raise Exception('Error %d running xcode-select' % job.returncode)
68 | dev_dir = out.decode('UTF-8').rstrip()
69 | sdk_dir = os.path.join(
70 | dev_dir, 'Platforms/MacOSX.platform/Developer/SDKs')
71 |
72 | if not os.path.isdir(sdk_dir):
73 | raise SdkError('Install Xcode, launch it, accept the license ' +
74 | 'agreement, and run `sudo xcode-select -s /path/to/Xcode.app` ' +
75 | 'to continue.')
76 | sdks = [re.findall('^MacOSX(\d+\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)]
77 | sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6']
78 | sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6']
79 | if parse_version(s) >= parse_version(min_sdk_version)]
80 | if not sdks:
81 | raise Exception('No %s+ SDK found' % min_sdk_version)
82 | best_sdk = sorted(sdks, key=parse_version)[0]
83 |
84 | if options.print_sdk_path:
85 | sdk_name = 'MacOSX' + best_sdk + '.sdk'
86 | print(os.path.join(sdk_dir, sdk_name))
87 |
88 | if options.print_bin_path:
89 | bin_path = 'Toolchains/XcodeDefault.xctoolchain/usr/bin/'
90 | print(os.path.join(dev_dir, bin_path))
91 |
92 | return best_sdk
93 |
94 |
95 | if __name__ == '__main__':
96 | if sys.platform != 'darwin':
97 | raise Exception("This script only runs on Mac")
98 | print(main())
99 | sys.exit(0)
100 |
--------------------------------------------------------------------------------
/toolchain/win/manifest.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # HOW MANIFESTS WORK IN THE GN BUILD
6 | #
7 | # Use the windows_manifest template to declare a manifest generation step.
8 | # This will combine all listed .manifest files. To link this manifest, just
9 | # depend on the manifest target from your executable or shared library.
10 | #
11 | # This will define an empty placeholder target on non-Windows platforms so
12 | # the manifest declarations and dependencies do not need to be inside of OS
13 | # conditionals.
14 | #
15 | # A binary can depend on only one manifest target, but the manifest target
16 | # can depend on many individual .manifest files which will be merged. As a
17 | # result, only executables and shared libraries should depend on manifest
18 | # targets. If you want to add a manifest to a component, put the dependency
19 | # behind a "if (is_component_build)" conditional.
20 | #
21 | # Generally you will just want the defaults for the Chrome build. In this case
22 | # the binary should just depend on one of the targets in //build/win/. There
23 | # are also individual manifest files in that directory you can reference via
24 | # the *_manifest variables defined below to pick and choose only some defaults.
25 | # You might combine these with a custom manifest file to get specific behavior.
26 |
27 | # Construct a target to combine the given manifest files into a .rc file.
28 | #
29 | # Variables for the windows_manifest template:
30 | #
31 | # sources: (required)
32 | # List of source .manifest files to add.
33 | #
34 | # deps: (optional)
35 | # visibility: (optional)
36 | # Normal meaning.
37 | #
38 | # Example:
39 | #
40 | # windows_manifest("doom_melon_manifest") {
41 | # sources = [
42 | # "doom_melon.manifest", # Custom values in here.
43 | # default_compatibility_manifest, # Want the normal OS compat list.
44 | # ]
45 | # }
46 | #
47 | # executable("doom_melon") {
48 | # deps = [ ":doom_melon_manifest" ]
49 | # ...
50 | # }
51 |
52 | if (is_win) {
53 | template("windows_manifest") {
54 | config_name = "${target_name}__config"
55 | source_set_name = target_name
56 |
57 | config(config_name) {
58 | visibility = [ ":$source_set_name" ]
59 | assert(defined(invoker.sources),
60 | "\"sources\" must be defined for a windows_manifest target")
61 | manifests = []
62 | foreach(i, rebase_path(invoker.sources, root_build_dir)) {
63 | manifests += [ "/manifestinput:" + i ]
64 | }
65 | ldflags = [
66 | "/manifest:embed",
67 |
68 | # We handle UAC by adding explicit .manifest files instead.
69 | "/manifestuac:no",
70 | ] + manifests
71 | }
72 |
73 | # This source set only exists to add a dep on the invoker's deps and to
74 | # add a public_config that sets ldflags on dependents.
75 | source_set(source_set_name) {
76 | forward_variables_from(invoker, [ "visibility" ])
77 | public_configs = [ ":$config_name" ]
78 |
79 | # Apply any dependencies from the invoker to this target, since those
80 | # dependencies may have created the input manifest files.
81 | forward_variables_from(invoker, [ "deps" ])
82 | }
83 | }
84 | } else {
85 | # Make a no-op group on non-Windows platforms so windows_manifest
86 | # instantiations don't need to be inside windows blocks.
87 | template("windows_manifest") {
88 | group(target_name) {
89 | # Prevent unused variable warnings on non-Windows platforms.
90 | assert(invoker.sources != "")
91 | assert(!defined(invoker.deps) || invoker.deps != "")
92 | assert(!defined(invoker.visibility) || invoker.visibility != "")
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/toolchain/mac/mac_sdk.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/mac/mac_sdk_overrides.gni")
6 | import("//build/toolchain/mac/settings.gni")
7 |
8 | assert(current_os == "mac" || current_toolchain == default_toolchain)
9 |
10 | declare_args() {
11 | # The MACOSX_DEPLOYMENT_TARGET variable used when compiling. This partially
12 | # controls the minimum supported version of macOS for Chromium by
13 | # affecting the symbol availability rules. This may differ from
14 | # mac_min_system_version when dropping support for older macOSes but where
15 | # additional code changes are required to be compliant with the availability
16 | # rules.
17 | # Must be of the form x.x.x for Info.plist files.
18 | mac_deployment_target = "10.11.0"
19 |
20 | # The value of the LSMinimmumSystemVersion in Info.plist files. This partially
21 | # controls the minimum supported version of macOS for Chromium by
22 | # affecting the Info.plist. This may differ from mac_deployment_target when
23 | # dropping support for older macOSes. This should be greater than or equal to
24 | # the mac_deployment_target version.
25 | # Must be of the form x.x.x for Info.plist files.
26 | mac_min_system_version = "10.11.0"
27 |
28 | # Path to a specific version of the Mac SDK, not including a slash at the end.
29 | # If empty, the path to the lowest version greater than or equal to
30 | # mac_sdk_min is used.
31 | mac_sdk_path = ""
32 |
33 | # The SDK name as accepted by xcodebuild.
34 | mac_sdk_name = "macosx"
35 |
36 | # The SDK version used when making official builds. This is a single exact
37 | # version, not a minimum. If this version isn't available official builds
38 | # will fail.
39 | mac_sdk_official_version = "10.15"
40 |
41 | # If Xcode is not installed, and you are going to build standard C/C++ code only,
42 | # you should set it to false.
43 | mac_use_sdk = true
44 | }
45 |
46 | sdk_info_args = []
47 | if (!use_system_xcode) {
48 | sdk_info_args += [
49 | "--developer_dir",
50 | rebase_path(hermetic_xcode_path, "", root_build_dir),
51 | ]
52 | }
53 |
54 | sdk_info_args += [ mac_sdk_name ]
55 |
56 | if (mac_use_sdk) {
57 | _mac_sdk_result = exec_script("//build/toolchain/apple/sdk_info.py", sdk_info_args, "scope")
58 | xcode_version = _mac_sdk_result.xcode_version
59 | xcode_build = _mac_sdk_result.xcode_build
60 |
61 | if (use_system_xcode) {
62 | # The tool will print the SDK path on the first line, and the version on the
63 | # second line.
64 | find_sdk_args = [
65 | "--print_sdk_path",
66 | "--print_bin_path",
67 | mac_sdk_min,
68 | ]
69 | find_sdk_lines =
70 | exec_script("//build/toolchain/mac/find_sdk.py", find_sdk_args, "list lines")
71 | mac_sdk_version = find_sdk_lines[2]
72 | if (mac_sdk_path == "") {
73 | mac_sdk_path = find_sdk_lines[0]
74 | mac_bin_path = find_sdk_lines[1]
75 | } else {
76 | mac_bin_path = find_sdk_lines[1]
77 | }
78 | } else {
79 | mac_sdk_version = mac_sdk_official_version
80 | _dev = hermetic_xcode_path + "/Contents/Developer"
81 | _sdk = "MacOSX${mac_sdk_version}.sdk"
82 | mac_sdk_path = _dev + "/Platforms/MacOSX.platform/Developer/SDKs/$_sdk"
83 | mac_bin_path = _dev + "/Toolchains/XcodeDefault.xctoolchain/usr/bin/"
84 |
85 | # If we're using hermetic Xcode, then we want the paths to be relative so that
86 | # generated ninja files are independent of the directory location.
87 | # TODO(thakis): Do this at the uses of this variable instead.
88 | mac_bin_path = rebase_path(mac_bin_path, root_build_dir)
89 | }
90 | } else {
91 | xcode_version = ""
92 | xcode_build = ""
93 | mac_sdk_version = ""
94 | mac_sdk_path = ""
95 | mac_bin_path = ""
96 | }
97 |
--------------------------------------------------------------------------------
/config/mac/BUILD.gn:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/config/libc++/settings.gni")
6 | import("//build/toolchain/apple/symbols.gni")
7 | import("//build/toolchain/mac/mac_sdk.gni")
8 | import("//build/toolchain/sysroot.gni")
9 |
10 | # This is included by reference in the //build/config/compiler config that
11 | # is applied to all targets. It is here to separate out the logic.
12 | config("compiler") {
13 | # These flags are shared between the C compiler and linker.
14 | common_mac_flags = []
15 |
16 | # CPU architecture.
17 | if (current_cpu == "x64") {
18 | clang_arch = "x86_64"
19 | } else if (current_cpu == "x86") {
20 | clang_arch = "i386"
21 | } else if (current_cpu == "armv7" || current_cpu == "arm") {
22 | clang_arch = "armv7"
23 | } else if (current_cpu == "arm64") {
24 | clang_arch = current_cpu
25 | } else {
26 | assert(false, "unknown current_cpu $current_cpu")
27 | }
28 | if (host_os == "mac") {
29 | common_mac_flags += [
30 | "-arch",
31 | clang_arch,
32 | ]
33 | } else {
34 | common_mac_flags += [ "--target=$clang_arch-apple-macos" ]
35 | }
36 |
37 | # This is here so that all files get recompiled after an Xcode update.
38 | # (defines are passed via the command line, and build system rebuild things
39 | # when their commandline changes). Nothing should ever read this define.
40 | if (mac_use_sdk) {
41 | defines = [ "CR_XCODE_VERSION=$xcode_version" ]
42 | }
43 |
44 | asmflags = common_mac_flags
45 | cflags = common_mac_flags
46 |
47 | # Without this, the constructors and destructors of a C++ object inside
48 | # an Objective C struct won't be called, which is very bad.
49 | cflags_objcc = [ "-fobjc-call-cxx-cdtors" ]
50 |
51 | ldflags = common_mac_flags
52 |
53 | if (save_unstripped_output) {
54 | ldflags += [ "-Wcrl,unstripped," + rebase_path(root_out_dir) ]
55 | }
56 |
57 | if (export_libcxxabi_from_executables) {
58 | ldflags += [ "-Wl,-undefined,dynamic_lookup" ]
59 | }
60 | }
61 |
62 | # This is included by reference in the //build/config/compiler:runtime_library
63 | # config that is applied to all targets. It is here to separate out the logic
64 | # that is Mac-only. Please see that target for advice on what should go in
65 | # :runtime_library vs. :compiler.
66 | config("runtime_library") {
67 | if (mac_use_sdk) {
68 | common_flags = [
69 | "-isysroot",
70 | rebase_path(sysroot, root_build_dir),
71 | "-mmacosx-version-min=$mac_deployment_target",
72 | ]
73 | } else {
74 | common_flags=[]
75 | }
76 |
77 | asmflags = common_flags
78 | cflags = common_flags
79 | ldflags = common_flags
80 |
81 | # Prevent Mac OS X AssertMacros.h (included by system header) from defining
82 | # macros that collide with common names, like 'check', 'require', and
83 | # 'verify'.
84 | # http://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/AssertMacros.h
85 | defines = [ "__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0" ]
86 | }
87 |
88 | # On Mac, this is used for everything except static libraries.
89 | config("mac_dynamic_flags") {
90 | ldflags = [
91 | # Always load Objective-C categories and classes.
92 | "-Wl,-ObjC",
93 |
94 | # Load shared libraries next to the target.
95 | "-Wl,-rpath,@loader_path/.",
96 | ]
97 | }
98 |
99 | # On Mac, this is used only for executables.
100 | config("mac_executable_flags") {
101 | # Remove this when targeting >=10.7 since it is the default in that config.
102 | ldflags = [ "-Wl,-pie" ] # Position independent.
103 | }
104 |
105 | # The ldflags referenced below are handled by
106 | # //build/toolchain/apple/linker_driver.py.
107 | # Remove this config if a target wishes to change the arguments passed to the
108 | # strip command during linking. This config by default strips all symbols
109 | # from a binary, but some targets may wish to specify an exports file to
110 | # preserve specific symbols.
111 | config("strip_all") {
112 | if (enable_stripping) {
113 | ldflags = [ "-Wcrl,strip,-x,-S" ]
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/.github/workflows/posix.yml:
--------------------------------------------------------------------------------
1 | name: POSIX
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - master
7 | - develop
8 | - feature/**
9 | push:
10 | branches:
11 | - master
12 | - develop
13 | - feature/**
14 | workflow_dispatch:
15 | release:
16 | types: published
17 |
18 | env:
19 | NINJA_BASE_URL: https://github.com/ninja-build/ninja/releases/download/
20 | GN_BASE_URL: https://github.com/timniederhausen/gn/releases/download/2021.03/
21 |
22 | jobs:
23 | posix:
24 | strategy:
25 | fail-fast: false
26 | matrix:
27 | include:
28 | - slug: linux-gcc-i386
29 | gen_args: 'gcc_cc="gcc-10" gcc_cxx="g++-10" target_cpu="x86" is_clang=false'
30 | os: ubuntu-22.04
31 | install: "g++-10-multilib"
32 | ninja_release_name: v1.7.2/ninja-linux.zip
33 | gn_release_name: gn-linux-amd64.tar.gz
34 |
35 | - slug: linux-gcc-amd64
36 | gen_args: 'gcc_cc="gcc-10" gcc_cxx="g++-10" target_cpu="x64" is_clang=false'
37 | os: ubuntu-22.04
38 | install: "g++-10"
39 | ninja_release_name: v1.7.2/ninja-linux.zip
40 | gn_release_name: gn-linux-amd64.tar.gz
41 |
42 | - slug: linux-clang-i386
43 | gen_args: 'clang_cc="clang-14" clang_cxx="clang++-14" target_cpu="x86" is_clang=true'
44 | os: ubuntu-22.04
45 | install: "clang-14 g++-multilib"
46 | ninja_release_name: v1.7.2/ninja-linux.zip
47 | gn_release_name: gn-linux-amd64.tar.gz
48 |
49 | - slug: linux-clang-amd64
50 | gen_args: 'clang_cc="clang-14" clang_cxx="clang++-14" target_cpu="x64" is_clang=true'
51 | os: ubuntu-22.04
52 | install: "clang-14"
53 | ninja_release_name: v1.7.2/ninja-linux.zip
54 | gn_release_name: gn-linux-amd64.tar.gz
55 |
56 | # disabled on master for now
57 | # see: https://github.com/timniederhausen/gn-build/runs/2483312992#step:9:24
58 | - slug: macos-amd64
59 | gen_args: 'is_clang=true is_official_build=true'
60 | os: macos-13
61 | ninja_release_name: v1.7.2/ninja-mac.zip
62 | gn_release_name: gn-macos-amd64.tar.gz
63 |
64 | runs-on: ${{ matrix.os }}
65 |
66 | steps:
67 | - name: Install packages
68 | if: matrix.install
69 | run: sudo apt install ${{ matrix.install }}
70 |
71 | - uses: actions/checkout@v4
72 | with:
73 | # we need all everything for `git describe` to work correctly
74 | fetch-depth: 0
75 |
76 | - name: Make dependencies directory
77 | run: |
78 | DEPS_DIR=$(cd ~; pwd)/deps
79 | mkdir -p ${DEPS_DIR}
80 | echo "export DEPS_DIR=$DEPS_DIR" >> "${GITHUB_WORKSPACE}/.env"
81 |
82 | - name: Install recent Ninja
83 | run: |
84 | source .env
85 | cd ${DEPS_DIR}
86 | wget --no-check-certificate --quiet -O ninja.zip "${NINJA_BASE_URL}${{ matrix.ninja_release_name }}"
87 | python -c 'import sys,zipfile;zipfile.ZipFile(sys.argv[1]).extractall()' ninja.zip
88 | chmod +x ninja
89 |
90 | - name: Install GN
91 | run: |
92 | source .env
93 | cd ${DEPS_DIR}
94 | wget --no-check-certificate --quiet -O gn.tgz "${GN_BASE_URL}${{ matrix.gn_release_name }}"
95 | tar xvf gn.tgz
96 | chmod +x gn
97 |
98 | # Run gn_helpers unittests first - this should fail if we have an unsupported Python version
99 | # Only support Python3+ for now, otherwise we have to ship the mocking lib
100 | - name: Test gn_helpers
101 | run: |
102 | python3 gn_helpers_unittest.py
103 |
104 | # Setup test project for our //build
105 | - name: Setup test project
106 | run: |
107 | source .env
108 | git clone --branch=testsrc --depth=1 https://github.com/timniederhausen/gn-build.git testsrc
109 | mkdir testsrc/build
110 | mv *.py testsrc/build/
111 | mv config testsrc/build/
112 | mv toolchain testsrc/build/
113 |
114 | # Try to generate ninja files with different python versions
115 | - name: gen with python3
116 | run: |
117 | source .env
118 | echo script_executable = \"python3\" >> testsrc/.gn
119 | ${DEPS_DIR}/gn gen out --args='${{ matrix.gen_args }}' --root=testsrc
120 |
121 | # Try to build the test project
122 | - name: Build
123 | run: |
124 | source .env
125 | cat out/args.gn
126 | ${DEPS_DIR}/ninja -C out
127 | cd out && ./hello
128 |
--------------------------------------------------------------------------------
/toolchain/win/settings.gni:
--------------------------------------------------------------------------------
1 | if (is_clang) {
2 | import("//build/toolchain/clang.gni")
3 | }
4 |
5 | declare_args() {
6 | # Desired version of Visual Studio.
7 | # If visual_studio_path is set, this must be
8 | # the version of the VS installation at the visual_studio_path.
9 | #
10 | # Use "2013" for Visual Studio 2013 or "latest" for automatically
11 | # choosing the highest version (visual_studio_path must be unset in
12 | # this case).
13 | visual_studio_version = "latest"
14 |
15 | # The path of your MSVC installation.
16 | #
17 | # If this is set you must set visual_studio_version as well.
18 | # Autodetected based on visual_studio_version.
19 | visual_studio_path = ""
20 |
21 | # Windows SDK version to use.
22 | # Can either be a full Windows 10 SDK number (e.g. 10.0.10240.0),
23 | # "8.1" for the Windows 8.1 SDK or "default" to use the VS default version.
24 | windows_sdk_version = "default"
25 |
26 | # Microsoft compiler version number clang-cl will report in _MSC_VER
27 | # (Defaults to the default version associated with the chosen VS version.)
28 | clang_msc_ver = 0
29 |
30 | # Allows us to avoid multiple toolchain.py invocations for multi-toolchain builds.
31 | cached_toolchain_data = ""
32 | }
33 |
34 | assert(visual_studio_version != "", "visual_studio_version must be non-empty")
35 | assert(visual_studio_path == "" || visual_studio_version != "latest",
36 | "You must set visual_studio_version if you set visual_studio_path")
37 |
38 | if (is_clang) {
39 | _clang_base_path_arg = clang_base_path
40 | _clang_msc_ver = "" + clang_msc_ver
41 | } else {
42 | _clang_base_path_arg = ""
43 | _clang_msc_ver = ""
44 | }
45 |
46 | if (host_os == "win") {
47 | clang_cl = "clang-cl.exe"
48 | } else {
49 | clang_cl = "clang-cl"
50 | }
51 |
52 | if (visual_studio_path == "") {
53 | # can't pass empty args
54 | visual_studio_path = "default"
55 | }
56 |
57 | if (cached_toolchain_data != "") {
58 | toolchain_data = cached_toolchain_data
59 | } else {
60 | toolchain_data = exec_script("toolchain.py",
61 | [
62 | "setup_toolchain",
63 | visual_studio_version,
64 | visual_studio_path,
65 | windows_sdk_version,
66 |
67 | # Don't use clang_base_path directly, so we can
68 | # skip clang detection if not needed
69 | # (i.e. !is_clang).
70 | _clang_base_path_arg,
71 | _clang_msc_ver,
72 | ],
73 | "scope")
74 | }
75 |
76 | visual_studio_version = toolchain_data.visual_studio_version
77 | visual_studio_path = toolchain_data.visual_studio_path
78 |
79 | # Full path to the Windows SDK, not including a backslash at the end.
80 | windows_sdk_path = toolchain_data.windows_sdk_path
81 |
82 | # Value of the _MSC_VER variable.
83 | # see: https://msdn.microsoft.com/en-us/library/b0084kay.aspx
84 | msc_ver = toolchain_data.msc_ver
85 |
86 | # Value of the _MSC_FULL_VER variable.
87 | # see: https://msdn.microsoft.com/en-us/library/b0084kay.aspx
88 | msc_full_ver = toolchain_data.msc_full_ver
89 |
90 | if (defined(toolchain_data.clang_version)) {
91 | win_clang_version = toolchain_data.clang_version
92 | } else {
93 | win_clang_version = 0
94 | }
95 |
96 | # current_toolchain_data: Settings specific to current_os/current_cpu
97 | if (current_os == "win") {
98 | if (current_cpu == "x86") {
99 | assert(defined(toolchain_data.x86))
100 | current_toolchain_data = toolchain_data.x86
101 | } else if (current_cpu == "x64") {
102 | assert(defined(toolchain_data.x64))
103 | current_toolchain_data = toolchain_data.x64
104 | } else if (current_cpu == "arm") {
105 | assert(defined(toolchain_data.arm))
106 | current_toolchain_data = toolchain_data.arm
107 | } else if (current_cpu == "arm64") {
108 | assert(defined(toolchain_data.arm64))
109 | current_toolchain_data = toolchain_data.arm64
110 | }
111 | } else if (current_os == "winuwp") {
112 | if (current_cpu == "x86") {
113 | assert(defined(toolchain_data.x86_uwp))
114 | current_toolchain_data = toolchain_data.x86_uwp
115 | } else if (current_cpu == "x64") {
116 | assert(defined(toolchain_data.x64_uwp))
117 | current_toolchain_data = toolchain_data.x64_uwp
118 | } else if (current_cpu == "arm") {
119 | assert(defined(toolchain_data.arm_uwp))
120 | current_toolchain_data = toolchain_data.arm_uwp
121 | } else if (current_cpu == "arm64") {
122 | assert(defined(toolchain_data.arm64_uwp))
123 | current_toolchain_data = toolchain_data.arm64_uwp
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/toolchain/gcc_solink_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2015 The Chromium Authors. All rights reserved.
3 | # Use of this source code is governed by a BSD-style license that can be
4 | # found in the LICENSE file.
5 |
6 | """Runs 'ld -shared' and generates a .TOC file that's untouched when unchanged.
7 |
8 | This script exists to avoid using complex shell commands in
9 | gcc_toolchain.gni's tool("solink"), in case the host running the compiler
10 | does not have a POSIX-like shell (e.g. Windows).
11 | """
12 |
13 | import argparse
14 | import os
15 | import subprocess
16 | import sys
17 |
18 | import wrapper_utils
19 |
20 |
21 | def CollectSONAME(args):
22 | """Replaces: readelf -d $sofile | grep SONAME"""
23 | toc = ''
24 | readelf = subprocess.Popen(wrapper_utils.CommandToRun(
25 | [args.readelf, '-d', args.sofile]), stdout=subprocess.PIPE,
26 | bufsize=-1, universal_newlines=True)
27 | for line in readelf.stdout:
28 | if 'SONAME' in line:
29 | toc += line
30 | return readelf.wait(), toc
31 |
32 |
33 | def CollectDynSym(args):
34 | """Replaces: nm --format=posix -g -D $sofile | cut -f1-2 -d' '"""
35 | toc = ''
36 | nm = subprocess.Popen(wrapper_utils.CommandToRun([
37 | args.nm, '--format=posix', '-g', '-D', args.sofile]),
38 | stdout=subprocess.PIPE, bufsize=-1, universal_newlines=True)
39 | for line in nm.stdout:
40 | toc += ' '.join(line.split(' ', 2)[:2]) + '\n'
41 | return nm.wait(), toc
42 |
43 |
44 | def CollectTOC(args):
45 | result, toc = CollectSONAME(args)
46 | if result == 0:
47 | result, dynsym = CollectDynSym(args)
48 | toc += dynsym
49 | return result, toc
50 |
51 |
52 | def UpdateTOC(tocfile, toc):
53 | if os.path.exists(tocfile):
54 | old_toc = open(tocfile, 'r').read()
55 | else:
56 | old_toc = None
57 | if toc != old_toc:
58 | open(tocfile, 'w').write(toc)
59 |
60 |
61 | def main():
62 | parser = argparse.ArgumentParser(description=__doc__)
63 | parser.add_argument('--readelf',
64 | required=True,
65 | help='The readelf binary to run',
66 | metavar='PATH')
67 | parser.add_argument('--nm',
68 | required=True,
69 | help='The nm binary to run',
70 | metavar='PATH')
71 | parser.add_argument('--strip',
72 | help='The strip binary to run',
73 | metavar='PATH')
74 | parser.add_argument('--sofile',
75 | required=True,
76 | help='Shared object file produced by linking command',
77 | metavar='FILE')
78 | parser.add_argument('--tocfile',
79 | required=True,
80 | help='Output table-of-contents file',
81 | metavar='FILE')
82 | parser.add_argument('--map-file',
83 | help=('Use --Wl,-Map to generate a map file. Will be '
84 | 'gzipped if extension ends with .gz'),
85 | metavar='FILE')
86 | parser.add_argument('--output',
87 | required=True,
88 | help='Final output shared object file',
89 | metavar='FILE')
90 | parser.add_argument('--resource-whitelist',
91 | help='Merge all resource whitelists into a single file.',
92 | metavar='PATH')
93 | parser.add_argument('command', nargs='+',
94 | help='Linking command')
95 | args = parser.parse_args()
96 |
97 | # Work-around for gold being slow-by-default. http://crbug.com/632230
98 | fast_env = dict(os.environ)
99 | fast_env['LC_ALL'] = 'C'
100 |
101 | if args.resource_whitelist:
102 | whitelist_candidates = wrapper_utils.ResolveRspLinks(args.command)
103 | wrapper_utils.CombineResourceWhitelists(
104 | whitelist_candidates, args.resource_whitelist)
105 |
106 | # First, run the actual link.
107 | command = wrapper_utils.CommandToRun(args.command)
108 | result = wrapper_utils.RunLinkWithOptionalMapFile(command, env=fast_env,
109 | map_file=args.map_file)
110 |
111 | if result != 0:
112 | return result
113 |
114 | # Next, generate the contents of the TOC file.
115 | result, toc = CollectTOC(args)
116 | if result != 0:
117 | return result
118 |
119 | # If there is an existing TOC file with identical contents, leave it alone.
120 | # Otherwise, write out the TOC file.
121 | UpdateTOC(args.tocfile, toc)
122 |
123 | # Finally, strip the linked shared object file (if desired).
124 | if args.strip:
125 | result = subprocess.call(wrapper_utils.CommandToRun(
126 | [args.strip, '--strip-unneeded', '-o', args.output, args.sofile]))
127 |
128 | return result
129 |
130 |
131 | if __name__ == "__main__":
132 | sys.exit(main())
133 |
--------------------------------------------------------------------------------
/toolchain/android/BUILD.gn:
--------------------------------------------------------------------------------
1 | # Copyright 2013 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/android/settings.gni")
6 | import("//build/toolchain/toolchain.gni")
7 | import("//build/toolchain/sysroot.gni")
8 | import("//build/toolchain/gcc_toolchain.gni")
9 | import("//build/toolchain/clang.gni")
10 |
11 | # The Android GCC toolchains share most of the same parameters, so we have this
12 | # wrapper around gcc_toolchain to avoid duplication of logic.
13 | #
14 | # Parameters:
15 | # - toolchain_root
16 | # Path to cpu-specific toolchain within the ndk.
17 | # - sysroot
18 | # Sysroot for this architecture.
19 | # - lib_dir
20 | # Subdirectory inside of sysroot where libs go.
21 | # - binary_prefix
22 | # Prefix of compiler executables.
23 | template("android_gcc_toolchain") {
24 | gcc_toolchain(target_name) {
25 | assert(defined(invoker.toolchain_args),
26 | "toolchain_args must be defined for android_gcc_toolchain()")
27 | toolchain_args = invoker.toolchain_args
28 | toolchain_args.current_os = "android"
29 |
30 | # Make our manually injected libs relative to the build dir.
31 | _ndk_lib =
32 | rebase_path(invoker.sysroot + "/" + invoker.lib_dir, root_build_dir)
33 |
34 | libs_section_prefix = "$_ndk_lib/crtbegin_dynamic.o"
35 | libs_section_postfix = "$_ndk_lib/crtend_android.o"
36 |
37 | solink_libs_section_prefix = "$_ndk_lib/crtbegin_so.o"
38 | solink_libs_section_postfix = "$_ndk_lib/crtend_so.o"
39 |
40 | _android_tool_prefix =
41 | "${invoker.toolchain_root}/bin/${invoker.binary_prefix}-"
42 |
43 | # The tools should be run relative to the build dir.
44 | _tool_prefix = rebase_path("$_android_tool_prefix", root_build_dir)
45 |
46 | # Use the clang specified by the toolchain if there is one. Otherwise fall
47 | # back to the global flag.
48 | if (defined(toolchain_args.is_clang)) {
49 | toolchain_uses_clang = toolchain_args.is_clang
50 | } else {
51 | toolchain_uses_clang = is_clang
52 | }
53 |
54 | if (toolchain_uses_clang) {
55 | _prefix = rebase_path("$clang_base_path/bin", root_build_dir)
56 | cc = "$_prefix/clang"
57 | cxx = "$_prefix/clang++"
58 | } else {
59 | cc = "${_tool_prefix}gcc"
60 | cxx = "${_tool_prefix}g++"
61 | }
62 | ar = _tool_prefix + "ar"
63 | ld = cxx
64 | readelf = _tool_prefix + "readelf"
65 | nm = _tool_prefix + "nm"
66 | strip = "${_tool_prefix}strip"
67 |
68 | # Don't use .cr.so for loadable_modules since they are always loaded via
69 | # absolute path.
70 | loadable_module_extension = ".so"
71 | }
72 | }
73 |
74 | template("android_gcc_toolchains_helper") {
75 | android_gcc_toolchain("android_$target_name") {
76 | forward_variables_from(invoker, "*")
77 | toolchain_args.is_clang = false
78 | }
79 |
80 | android_gcc_toolchain("android_clang_$target_name") {
81 | forward_variables_from(invoker, "*")
82 | toolchain_args.is_clang = true
83 | }
84 | }
85 |
86 | android_gcc_toolchains_helper("x86") {
87 | toolchain_root = x86_android_toolchain_root
88 | sysroot = "$android_ndk_root/$x86_android_sysroot_subdir"
89 | lib_dir = "usr/lib"
90 | binary_prefix = "i686-linux-android"
91 | toolchain_args = {
92 | current_cpu = "x86"
93 | }
94 | }
95 |
96 | android_gcc_toolchains_helper("arm") {
97 | toolchain_root = arm_android_toolchain_root
98 | sysroot = "$android_ndk_root/$arm_android_sysroot_subdir"
99 | lib_dir = "usr/lib"
100 | binary_prefix = "arm-linux-androideabi"
101 | toolchain_args = {
102 | current_cpu = "arm"
103 | }
104 | }
105 |
106 | android_gcc_toolchains_helper("mipsel") {
107 | toolchain_root = mips_android_toolchain_root
108 | sysroot = "$android_ndk_root/$mips_android_sysroot_subdir"
109 | lib_dir = "usr/lib"
110 | binary_prefix = "mipsel-linux-android"
111 | toolchain_args = {
112 | current_cpu = "mipsel"
113 | }
114 | }
115 |
116 | android_gcc_toolchains_helper("x64") {
117 | toolchain_root = x86_64_android_toolchain_root
118 | sysroot = "$android_ndk_root/$x86_64_android_sysroot_subdir"
119 | lib_dir = "usr/lib64"
120 | binary_prefix = "x86_64-linux-android"
121 | toolchain_args = {
122 | current_cpu = "x64"
123 | }
124 | }
125 |
126 | android_gcc_toolchains_helper("arm64") {
127 | toolchain_root = arm64_android_toolchain_root
128 | sysroot = "$android_ndk_root/$arm64_android_sysroot_subdir"
129 | lib_dir = "usr/lib"
130 | binary_prefix = "aarch64-linux-android"
131 | toolchain_args = {
132 | current_cpu = "arm64"
133 | }
134 | }
135 |
136 | android_gcc_toolchains_helper("mips64el") {
137 | toolchain_root = mips64_android_toolchain_root
138 | sysroot = "$android_ndk_root/$mips64_android_sysroot_subdir"
139 | lib_dir = "usr/lib64"
140 | binary_prefix = "mips64el-linux-android"
141 | toolchain_args = {
142 | current_cpu = "mips64el"
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/toolchain/wrapper_utils.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | """Helper functions for gcc_toolchain.gni wrappers."""
6 |
7 | import gzip
8 | import os
9 | import re
10 | import subprocess
11 | import shlex
12 | import shutil
13 | import sys
14 | import threading
15 |
16 | _BAT_PREFIX = 'cmd /c call '
17 | _WHITELIST_RE = re.compile('whitelisted_resource_(?P[0-9]+)')
18 |
19 |
20 | def _GzipThenDelete(src_path, dest_path):
21 | # Results for Android map file with GCC on a z620:
22 | # Uncompressed: 207MB
23 | # gzip -9: 16.4MB, takes 8.7 seconds.
24 | # gzip -1: 21.8MB, takes 2.0 seconds.
25 | # Piping directly from the linker via -print-map (or via -Map with a fifo)
26 | # adds a whopping 30-45 seconds!
27 | with open(src_path, 'rb') as f_in, gzip.GzipFile(dest_path, 'wb', 1) as f_out:
28 | shutil.copyfileobj(f_in, f_out)
29 | os.unlink(src_path)
30 |
31 |
32 | def CommandToRun(command):
33 | """Generates commands compatible with Windows.
34 |
35 | When running on a Windows host and using a toolchain whose tools are
36 | actually wrapper scripts (i.e. .bat files on Windows) rather than binary
37 | executables, the |command| to run has to be prefixed with this magic.
38 | The GN toolchain definitions take care of that for when GN/Ninja is
39 | running the tool directly. When that command is passed in to this
40 | script, it appears as a unitary string but needs to be split up so that
41 | just 'cmd' is the actual command given to Python's subprocess module.
42 |
43 | Args:
44 | command: List containing the UNIX style |command|.
45 |
46 | Returns:
47 | A list containing the Windows version of the |command|.
48 | """
49 | if command[0].startswith(_BAT_PREFIX):
50 | command = command[0].split(None, 3) + command[1:]
51 | return command
52 |
53 |
54 | def RunLinkWithOptionalMapFile(command, env=None, map_file=None):
55 | """Runs the given command, adding in -Wl,-Map when |map_file| is given.
56 |
57 | Also takes care of gzipping when |map_file| ends with .gz.
58 |
59 | Args:
60 | command: List of arguments comprising the command.
61 | env: Environment variables.
62 | map_file: Path to output map_file.
63 |
64 | Returns:
65 | The exit code of running |command|.
66 | """
67 | tmp_map_path = None
68 | if map_file and map_file.endswith('.gz'):
69 | tmp_map_path = map_file + '.tmp'
70 | command.append('-Wl,-Map,' + tmp_map_path)
71 | elif map_file:
72 | command.append('-Wl,-Map,' + map_file)
73 |
74 | result = subprocess.call(command, env=env)
75 |
76 | if tmp_map_path and result == 0:
77 | threading.Thread(
78 | target=lambda: _GzipThenDelete(tmp_map_path, map_file)).start()
79 | elif tmp_map_path and os.path.exists(tmp_map_path):
80 | os.unlink(tmp_map_path)
81 |
82 | return result
83 |
84 |
85 | def ResolveRspLinks(inputs):
86 | """Return a list of files contained in a response file.
87 |
88 | Args:
89 | inputs: A command containing rsp files.
90 |
91 | Returns:
92 | A set containing the rsp file content."""
93 | rspfiles = [a[1:] for a in inputs if a.startswith('@')]
94 | resolved = set()
95 | for rspfile in rspfiles:
96 | with open(rspfile, 'r') as f:
97 | resolved.update(shlex.split(f.read()))
98 |
99 | return resolved
100 |
101 |
102 | def CombineResourceWhitelists(whitelist_candidates, outfile):
103 | """Combines all whitelists for a resource file into a single whitelist.
104 |
105 | Args:
106 | whitelist_candidates: List of paths to rsp files containing all targets.
107 | outfile: Path to save the combined whitelist.
108 | """
109 | whitelists = ('%s.whitelist' % candidate for candidate in whitelist_candidates
110 | if os.path.exists('%s.whitelist' % candidate))
111 |
112 | resources = set()
113 | for whitelist in whitelists:
114 | with open(whitelist, 'r') as f:
115 | resources.update(f.readlines())
116 |
117 | with open(outfile, 'w') as f:
118 | f.writelines(resources)
119 |
120 |
121 | def ExtractResourceIdsFromPragmaWarnings(text):
122 | """Returns set of resource IDs that are inside unknown pragma warnings.
123 |
124 | Args:
125 | text: The text that will be scanned for unknown pragma warnings.
126 |
127 | Returns:
128 | A set containing integers representing resource IDs.
129 | """
130 | used_resources = set()
131 | lines = text.splitlines()
132 | for ln in lines:
133 | match = _WHITELIST_RE.search(ln)
134 | if match:
135 | resource_id = int(match.group('resource_id'))
136 | used_resources.add(resource_id)
137 |
138 | return used_resources
139 |
140 |
141 | def CaptureCommandStderr(command, env=None):
142 | """Returns the stderr of a command.
143 |
144 | Args:
145 | command: A list containing the command and arguments.
146 | env: Environment variables for the new process.
147 | """
148 | child = subprocess.Popen(command, stderr=subprocess.PIPE, env=env,
149 | universal_newlines=True)
150 | _, stderr = child.communicate()
151 | return child.returncode, stderr
152 |
--------------------------------------------------------------------------------
/config/libc++/BUILD.gn:
--------------------------------------------------------------------------------
1 | import("//build/config/libc++/c++.gni")
2 |
3 | assert(use_custom_libcxx, "should only be used if use_custom_libcxx is set")
4 |
5 | declare_args() {
6 | # lldb pretty printing only works when libc++ is built in the __1 (or __ndk1)
7 | # namespaces. For pretty printing to work out-of-the-box on Mac (where lldb
8 | # is primarily used), this flag is set to false to build with the __1
9 | # namespace (to maintain ABI compatibility, this implies building without
10 | # _LIBCPP_ABI_UNSTABLE). This is not necessary on non-component builds
11 | # because we leave the ABI version set to __1 in that case because libc++
12 | # symbols are not exported.
13 | # TODO(thomasanderson): Set this to true by default once rL352899 is available
14 | # in MacOS's lldb.
15 | libcxx_abi_unstable = !(is_apple && is_debug && is_component_build)
16 | }
17 |
18 | # This is included by reference in the //build/config/compiler:runtime_library
19 | # config that is applied to all targets. It is here to separate out the logic
20 | # that is specific to libc++. Please see that target for advice on what should
21 | # go in :runtime_library vs. :compiler.
22 | config("runtime_library") {
23 | cflags = []
24 | cflags_cc = []
25 | defines = []
26 | ldflags = []
27 | libs = []
28 |
29 | if (libcxx_abi_unstable) {
30 | defines += [ "_LIBCPP_ABI_UNSTABLE" ]
31 | }
32 |
33 | if (libcxx_is_shared) {
34 | # When libcxx_is_shared is true, symbols from libc++.so are exported for
35 | # all DSOs to use. If the system libc++ gets loaded (indirectly through
36 | # a system library), then it will conflict with our libc++.so. Add a
37 | # custom ABI version if we're building with _LIBCPP_ABI_UNSTABLE to avoid
38 | # conflicts.
39 | #
40 | # Windows doesn't need to set _LIBCPP_ABI_VERSION since there's no system
41 | # C++ library we could conflict with.
42 | if (libcxx_abi_unstable && !is_win) {
43 | defines += [ "_LIBCPP_ABI_VERSION=Cr" ]
44 | }
45 | } else {
46 | # Don't leak any symbols on a static build.
47 | defines += [ "_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS" ]
48 | if (!export_libcxxabi_from_executables && !is_win) {
49 | defines += [ "_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS" ]
50 | }
51 | }
52 |
53 | defines += [
54 | "_LIBCPP_ENABLE_NODISCARD",
55 |
56 | # TODO(crbug.com/1166707): libc++ requires this macro.
57 | "_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS",
58 | ]
59 |
60 | # Work around a symbol conflict between GRPC and the Fuchsia SDK.
61 | # TODO(crbug.com/1166970): Remove this when resolved.
62 | if (is_fuchsia) {
63 | defines += [ "_LIBCPP_NO_NATIVE_SEMAPHORES" ]
64 | }
65 |
66 | # libc++ has two levels of debug mode. Setting _LIBCPP_DEBUG to zero
67 | # enables most assertions. Setting it to one additionally enables iterator
68 | # debugging. See https://libcxx.llvm.org/docs/DesignDocs/DebugMode.html
69 | if (enable_iterator_debugging) {
70 | defines += [ "_LIBCPP_DEBUG=1" ]
71 | } else if (is_debug || dcheck_always_on) {
72 | defines += [ "_LIBCPP_DEBUG=0" ]
73 | }
74 |
75 | if (is_win) {
76 | # Intentionally not using libc++abi on Windows because libc++abi only
77 | # implements the Itanium C++ ABI, and not the Microsoft ABI which we use on
78 | # Windows (and we need to use in order to interoperate correctly with COM
79 | # among other things).
80 | assert(!export_libcxxabi_from_executables,
81 | "Don't use libcxxabi on Windows.")
82 |
83 | cflags_cc +=
84 | [ "-I" + rebase_path("$libcxx_prefix/include", root_build_dir) ]
85 |
86 | # Prevent libc++ from embedding linker flags to try to automatically link
87 | # against its runtime library. This is unnecessary with our build system,
88 | # and can also result in build failures if libc++'s name for a library
89 | # does not match ours.
90 | defines += [ "_LIBCPP_NO_AUTO_LINK" ]
91 |
92 | if (is_component_build) {
93 | # TODO(crbug.com/1090975): Disable the exclude_from_explicit_instantiation
94 | # to work around compiler bugs in the interaction between it and
95 | # dllimport/dllexport.
96 | defines += [ "_LIBCPP_HIDE_FROM_ABI=_LIBCPP_HIDDEN" ]
97 | }
98 |
99 | # Add a debug visualizer for Microsoft's debuggers so that they can display
100 | # libc++ types well.
101 | if (libcxx_natvis_include) {
102 | # chrome.natvis listed as an input in //buildtools/third_party/libc++ to
103 | # guarantee relinking on changes.
104 | ldflags += [ "/NATVIS:" + rebase_path("libc++.natvis", root_build_dir) ]
105 | }
106 | } else {
107 | cflags_cc += [
108 | "-nostdinc++",
109 | "-isystem" + rebase_path("$libcxx_prefix/include", root_build_dir),
110 | "-isystem" + rebase_path("$libcxxabi_prefix/include", root_build_dir),
111 | ]
112 | cflags_objcc = cflags_cc
113 |
114 | defines += [ "CR_LIBCXX_REVISION=$libcxx_revision" ]
115 |
116 | # Make sure we don't link against the system libstdc++ or libc++.
117 | if (is_clang) {
118 | ldflags += [ "-nostdlib++" ]
119 | } else {
120 | # Gcc has a built-in abs() definition with default visibility.
121 | # If it was not disabled, it would conflict with libc++'s abs()
122 | # with hidden visibility.
123 | cflags += [ "-fno-builtin-abs" ]
124 |
125 | ldflags += [ "-nodefaultlibs" ]
126 |
127 | # Unfortunately, there's no way to disable linking against just libc++
128 | # (gcc doesn't have -notstdlib++:
129 | # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83931); -nodefaultlibs
130 | # removes all of the default libraries, so add back the ones that we need.
131 | libs += [
132 | "c",
133 | "gcc_s",
134 | "m",
135 | "rt",
136 | ]
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/compiled_action.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # This file introduces two related templates that act like action and
6 | # action_foreach but instead of running a Python script, it will compile a
7 | # given tool in the host toolchain and run that (either once or over the list
8 | # of inputs, depending on the variant).
9 | #
10 | # Parameters
11 | #
12 | # tool (required)
13 | # [label] Label of the tool to run. This should be an executable, and
14 | # this label should not include a toolchain (anything in parens). The
15 | # host compile of this tool will be used.
16 | #
17 | # outputs (required)
18 | # [list of files] Like the outputs of action (if using "compiled_action",
19 | # this would be just the list of outputs), or action_foreach (if using
20 | # "compiled_action_foreach", this would contain source expansions mapping
21 | # input to output files).
22 | #
23 | # args (required)
24 | # [list of strings] Same meaning as action/action_foreach.
25 | #
26 | # inputs (optional)
27 | # Files the binary takes as input. The step will be re-run whenever any
28 | # of these change. If inputs is empty, the step will run only when the
29 | # binary itself changes.
30 | #
31 | # depfile
32 | # deps
33 | # visibility (all optional)
34 | # Same meaning as action/action_foreach.
35 | #
36 | #
37 | # Example of usage:
38 | #
39 | # compiled_action("run_my_tool") {
40 | # tool = "//tools/something:mytool"
41 | # outputs = [
42 | # "$target_gen_dir/mysource.cc",
43 | # "$target_gen_dir/mysource.h",
44 | # ]
45 | #
46 | # # The tool takes this input.
47 | # inputs = [ "my_input_file.idl" ]
48 | #
49 | # # In this case, the tool takes as arguments the input file and the output
50 | # # build dir (both relative to the "cd" that the script will be run in)
51 | # # and will produce the output files listed above.
52 | # args = [
53 | # rebase_path("my_input_file.idl", root_build_dir),
54 | # "--output-dir", rebase_path(target_gen_dir, root_build_dir),
55 | # ]
56 | # }
57 | #
58 | # You would typically declare your tool like this:
59 | # if (host_toolchain == current_toolchain) {
60 | # executable("mytool") {
61 | # ...
62 | # }
63 | # }
64 | # The if statement around the executable is optional. That says "I only care
65 | # about this target in the host toolchain". Usually this is what you want, and
66 | # saves unnecessarily compiling your tool for the target platform. But if you
67 | # need a target build of your tool as well, just leave off the if statement.
68 |
69 | if (host_os == "win") {
70 | _host_executable_suffix = ".exe"
71 | } else {
72 | _host_executable_suffix = ""
73 | }
74 |
75 | template("compiled_action") {
76 | assert(defined(invoker.tool), "tool must be defined for $target_name")
77 | assert(defined(invoker.outputs), "outputs must be defined for $target_name")
78 | assert(defined(invoker.args), "args must be defined for $target_name")
79 |
80 | assert(!defined(invoker.sources),
81 | "compiled_action doesn't take a sources arg. Use inputs instead.")
82 |
83 | action(target_name) {
84 | forward_variables_from(invoker,
85 | [
86 | "data_deps",
87 | "deps",
88 | "depfile",
89 | "inputs",
90 | "outputs",
91 | "testonly",
92 | "visibility",
93 | ])
94 | if (!defined(deps)) {
95 | deps = []
96 | }
97 | if (!defined(inputs)) {
98 | inputs = []
99 | }
100 |
101 | script = "//build/gn_run_binary.py"
102 |
103 | # Constuct the host toolchain version of the tool.
104 | host_tool = invoker.tool + "($host_toolchain)"
105 |
106 | # Get the path to the executable. Currently, this assumes that the tool
107 | # does not specify output_name so that the target name is the name to use.
108 | # If that's not the case, we'll need another argument to the script to
109 | # specify this, since we can't know what the output name is (it might be in
110 | # another file not processed yet).
111 | host_executable =
112 | get_label_info(host_tool, "root_out_dir") + "/" +
113 | get_label_info(host_tool, "name") + _host_executable_suffix
114 |
115 | deps += [ host_tool ]
116 |
117 | # The script takes as arguments the binary to run, and then the arguments
118 | # to pass it.
119 | args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args
120 | }
121 | }
122 |
123 | template("compiled_action_foreach") {
124 | assert(defined(invoker.sources), "sources must be defined for $target_name")
125 | assert(defined(invoker.tool), "tool must be defined for $target_name")
126 | assert(defined(invoker.outputs), "outputs must be defined for $target_name")
127 | assert(defined(invoker.args), "args must be defined for $target_name")
128 |
129 | action_foreach(target_name) {
130 | forward_variables_from(invoker,
131 | [
132 | "deps",
133 | "depfile",
134 | "inputs",
135 | "outputs",
136 | "sources",
137 | "testonly",
138 | "visibility",
139 | ])
140 | if (!defined(deps)) {
141 | deps = []
142 | }
143 | if (!defined(inputs)) {
144 | inputs = []
145 | }
146 |
147 | script = "//build/gn_run_binary.py"
148 |
149 | # Constuct the host toolchain version of the tool.
150 | host_tool = invoker.tool + "($host_toolchain)"
151 |
152 | # Get the path to the executable. Currently, this assumes that the tool
153 | # does not specify output_name so that the target name is the name to use.
154 | # If that's not the case, we'll need another argument to the script to
155 | # specify this, since we can't know what the output name is (it might be in
156 | # another file not processed yet).
157 | host_executable =
158 | get_label_info(host_tool, "root_out_dir") + "/" +
159 | get_label_info(host_tool, "name") + _host_executable_suffix
160 |
161 | deps += [ host_tool ]
162 |
163 | # The script takes as arguments the binary to run, and then the arguments
164 | # to pass it.
165 | args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/toolchain/apple/sdk_info.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | from __future__ import print_function
6 |
7 | import argparse
8 | import doctest
9 | import itertools
10 | import os
11 | import plistlib
12 | import re
13 | import subprocess
14 | import sys
15 |
16 | if sys.version_info.major < 3:
17 | basestring_compat = basestring
18 | else:
19 | basestring_compat = str
20 |
21 | # src directory
22 | ROOT_SRC_DIR = os.path.dirname(
23 | os.path.dirname(os.path.dirname(os.path.dirname(
24 | os.path.realpath(__file__)))))
25 |
26 | # This script prints information about the build system, the operating
27 | # system and the iOS or Mac SDK (depending on the platform "iphonesimulator",
28 | # "iphoneos" or "macosx" generally).
29 |
30 |
31 | def LoadPList(path):
32 | """Loads Plist at |path| and returns it as a dictionary."""
33 | # Cloned from //build/apple/plist_util.py.
34 | if sys.version_info.major == 2:
35 | return plistlib.readPlist(path)
36 | with open(path, 'rb') as f:
37 | return plistlib.load(f)
38 |
39 |
40 | def SplitVersion(version):
41 | """Splits the Xcode version to 3 values.
42 |
43 | >>> list(SplitVersion('8.2.1.1'))
44 | ['8', '2', '1']
45 | >>> list(SplitVersion('9.3'))
46 | ['9', '3', '0']
47 | >>> list(SplitVersion('10.0'))
48 | ['10', '0', '0']
49 | """
50 | version = version.split('.')
51 | return itertools.islice(itertools.chain(version, itertools.repeat('0')), 0, 3)
52 |
53 |
54 | def FormatVersion(version):
55 | """Converts Xcode version to a format required for DTXcode in Info.plist
56 |
57 | >>> FormatVersion('8.2.1')
58 | '0821'
59 | >>> FormatVersion('9.3')
60 | '0930'
61 | >>> FormatVersion('10.0')
62 | '1000'
63 | """
64 | major, minor, patch = SplitVersion(version)
65 | return ('%2s%s%s' % (major, minor, patch)).replace(' ', '0')
66 |
67 |
68 | def FillXcodeVersion(settings, developer_dir):
69 | """Fills the Xcode version and build number into |settings|."""
70 | if developer_dir:
71 | xcode_version_plist_path = os.path.join(developer_dir,
72 | 'Contents/version.plist')
73 | version_plist = LoadPList(xcode_version_plist_path)
74 | settings['xcode_version'] = FormatVersion(
75 | version_plist['CFBundleShortVersionString'])
76 | settings['xcode_version_int'] = int(settings['xcode_version'], 10)
77 | settings['xcode_build'] = version_plist['ProductBuildVersion']
78 | return
79 |
80 | lines = subprocess.check_output(['xcodebuild',
81 | '-version']).decode('UTF-8').splitlines()
82 | settings['xcode_version'] = FormatVersion(lines[0].split()[-1])
83 | settings['xcode_version_int'] = int(settings['xcode_version'], 10)
84 | settings['xcode_build'] = lines[-1].split()[-1]
85 |
86 |
87 | def FillMachineOSBuild(settings):
88 | """Fills OS build number into |settings|."""
89 | machine_os_build = subprocess.check_output(['sw_vers', '-buildVersion'
90 | ]).decode('UTF-8').strip()
91 | settings['machine_os_build'] = machine_os_build
92 |
93 |
94 | def FillSDKPathAndVersion(settings, platform, xcode_version):
95 | """Fills the SDK path and version for |platform| into |settings|."""
96 | settings['sdk_path'] = subprocess.check_output(
97 | ['xcrun', '-sdk', platform, '--show-sdk-path']).decode('UTF-8').strip()
98 | settings['sdk_version'] = subprocess.check_output(
99 | ['xcrun', '-sdk', platform,
100 | '--show-sdk-version']).decode('UTF-8').strip()
101 | settings['sdk_platform_path'] = subprocess.check_output(
102 | ['xcrun', '-sdk', platform,
103 | '--show-sdk-platform-path']).decode('UTF-8').strip()
104 | settings['sdk_build'] = subprocess.check_output(
105 | ['xcrun', '-sdk', platform,
106 | '--show-sdk-build-version']).decode('UTF-8').strip()
107 | settings['toolchains_path'] = os.path.join(
108 | subprocess.check_output(['xcode-select',
109 | '-print-path']).decode('UTF-8').strip(),
110 | 'Toolchains/XcodeDefault.xctoolchain')
111 |
112 |
113 | def CreateXcodeSymlinkAt(src, dst):
114 | """Create symlink to Xcode directory at target location."""
115 |
116 | if not os.path.isdir(dst):
117 | os.makedirs(dst)
118 |
119 | dst = os.path.join(dst, os.path.basename(src))
120 | updated_value = '//' + os.path.relpath(dst, ROOT_SRC_DIR)
121 |
122 | # Update the symlink only if it is different from the current destination.
123 | if os.path.islink(dst):
124 | current_src = os.readlink(dst)
125 | if current_src == src:
126 | return updated_value
127 | os.unlink(dst)
128 | sys.stderr.write('existing symlink %s points %s; want %s. Removed.' %
129 | (dst, current_src, src))
130 | os.symlink(src, dst)
131 | return updated_value
132 |
133 |
134 | if __name__ == '__main__':
135 | doctest.testmod()
136 |
137 | parser = argparse.ArgumentParser()
138 | parser.add_argument("--developer_dir", dest="developer_dir", required=False)
139 | parser.add_argument("--get_sdk_info",
140 | action="store_true",
141 | dest="get_sdk_info",
142 | default=False,
143 | help="Returns SDK info in addition to xcode info.")
144 | parser.add_argument("--get_machine_info",
145 | action="store_true",
146 | dest="get_machine_info",
147 | default=False,
148 | help="Returns machine info in addition to xcode info.")
149 | parser.add_argument("--create_symlink_at",
150 | action="store",
151 | dest="create_symlink_at",
152 | help="Create symlink of SDK at given location and "
153 | "returns the symlinked paths as SDK info instead "
154 | "of the original location.")
155 | args, unknownargs = parser.parse_known_args()
156 | if args.developer_dir:
157 | os.environ['DEVELOPER_DIR'] = args.developer_dir
158 |
159 | if len(unknownargs) != 1:
160 | sys.stderr.write('usage: %s [iphoneos|iphonesimulator|macosx]\n' %
161 | os.path.basename(sys.argv[0]))
162 | sys.exit(1)
163 |
164 | settings = {}
165 | if args.get_machine_info:
166 | FillMachineOSBuild(settings)
167 | FillXcodeVersion(settings, args.developer_dir)
168 | if args.get_sdk_info:
169 | FillSDKPathAndVersion(settings, unknownargs[0], settings['xcode_version'])
170 |
171 | for key in sorted(settings):
172 | value = settings[key]
173 | if args.create_symlink_at and '_path' in key:
174 | value = CreateXcodeSymlinkAt(value, args.create_symlink_at)
175 | if isinstance(value, basestring_compat):
176 | value = '"%s"' % value
177 | print('%s=%s' % (key, value))
178 |
--------------------------------------------------------------------------------
/config/android/BUILD.gn:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import("//build/toolchain/android/settings.gni")
6 | import("//build/config/sanitizers/sanitizers.gni")
7 |
8 | assert(is_android)
9 |
10 | # This is included by reference in the //build/config/compiler config that
11 | # is applied to all targets. It is here to separate out the logic that is
12 | # Android-only.
13 | config("compiler") {
14 | cflags = [
15 | "-ffunction-sections",
16 | "-fno-short-enums",
17 | ]
18 | defines = [
19 | "ANDROID",
20 |
21 | # The NDK has these things, but doesn't define the constants to say that it
22 | # does. Define them here instead.
23 | "HAVE_SYS_UIO_H",
24 |
25 | # Forces full rebuilds on NDK rolls.
26 | "ANDROID_NDK_VERSION=${android_ndk_version}",
27 | ]
28 |
29 | if (is_clang) {
30 | rebased_android_toolchain_root =
31 | rebase_path(android_toolchain_root, root_build_dir)
32 | assert(rebased_android_toolchain_root != "") # Mark as used.
33 | if (current_cpu == "mipsel" || current_cpu == "mips64el") {
34 | cflags += [
35 | # TODO(gordanac) Enable integrated-as.
36 | "-fno-integrated-as",
37 | "-B${rebased_android_toolchain_root}/bin", # Else /usr/bin/as gets picked up.
38 | ]
39 | }
40 | } else {
41 | # Clang doesn't support these flags.
42 | cflags += [ "-finline-limit=64" ]
43 | }
44 |
45 | ldflags = [
46 | "-Wl,--build-id=sha1",
47 | "-Wl,--no-undefined",
48 |
49 | # Don't allow visible symbols from libgcc or libc++ to be
50 | # re-exported.
51 | "-Wl,--exclude-libs=libgcc.a",
52 | "-Wl,--exclude-libs=libc++_static.a",
53 | ]
54 |
55 | if (is_clang) {
56 | _rebased_android_toolchain_root =
57 | rebase_path(android_toolchain_root, root_build_dir)
58 |
59 | # Let clang find the linker in the NDK.
60 | ldflags += [ "--gcc-toolchain=$_rebased_android_toolchain_root" ]
61 |
62 | if (current_cpu == "arm") {
63 | abi_target = "arm-linux-androideabi"
64 | } else if (current_cpu == "x86") {
65 | abi_target = "i686-linux-androideabi"
66 | } else if (current_cpu == "arm64") {
67 | abi_target = "aarch64-linux-android"
68 | } else if (current_cpu == "x64") {
69 | # Place holder for x64 support, not tested.
70 | # TODO: Enable clang support for Android x64. http://crbug.com/539781
71 | abi_target = "x86_64-linux-androideabi"
72 | } else if (current_cpu == "mipsel") {
73 | abi_target = "mipsel-linux-android"
74 | } else if (current_cpu == "mips64el") {
75 | # Place holder for mips64 support, not tested.
76 | abi_target = "mips64el-linux-androideabi"
77 | } else {
78 | assert(false, "Architecture not supported")
79 | }
80 | cflags += [ "--target=$abi_target" ]
81 | ldflags += [ "--target=$abi_target" ]
82 | }
83 |
84 | # Assign any flags set for the C compiler to asmflags so that they are sent
85 | # to the assembler.
86 | asmflags = cflags
87 | }
88 |
89 | # This is included by reference in the //build/config:runtime_library
90 | # config that is applied to all targets. It is here to separate out the logic
91 | # that is Android-only. Please see that target for advice on what should go in
92 | # :runtime_library vs. :compiler.
93 | config("runtime_library") {
94 | # NOTE: The libc++ header include paths below are specified in cflags_cc
95 | # rather than include_dirs because they need to come after include_dirs.
96 | # Think of them like system headers, but don't use '-isystem' because the
97 | # arm-linux-androideabi-4.4.3 toolchain (circa Gingerbread) will exhibit
98 | # strange errors. The include ordering here is important; change with
99 | # caution.
100 | cflags_cc = []
101 | if (android_ndk_major_version >= 13) {
102 | libcxx_include_path =
103 | rebase_path("$android_libcpp_root/include", root_build_dir)
104 | libcxxabi_include_path =
105 | rebase_path("$android_ndk_root/sources/cxx-stl/llvm-libc++abi/include",
106 | root_build_dir)
107 |
108 | if (!is_clang) {
109 | # Per the release notes, GCC is not supported in the NDK starting with
110 | # r13. It's still present, though, and has conflicting declarations of
111 | # float abs(float).
112 | cflags_cc += [ "-Wno-attributes" ]
113 | }
114 | } else {
115 | libcxx_include_path =
116 | rebase_path("$android_libcpp_root/libcxx/include", root_build_dir)
117 | libcxxabi_include_path = rebase_path(
118 | "$android_ndk_root/sources/cxx-stl/llvm-libc++abi/libcxxabi/include",
119 | root_build_dir)
120 | }
121 | cflags_cc += [
122 | "-isystem" + libcxx_include_path,
123 | "-isystem" + libcxxabi_include_path,
124 | "-isystem" +
125 | rebase_path("$android_ndk_root/sources/android/support/include",
126 | root_build_dir),
127 | ]
128 |
129 | defines = [ "__GNU_SOURCE=1" ] # Necessary for clone().
130 | ldflags = [ "-nostdlib" ]
131 | lib_dirs = [ android_libcpp_lib_dir ]
132 |
133 | # The libc++ runtime library (must come first).
134 | # ASan needs to dynamically link to libc++ even in static builds so
135 | # that it can interpose operator new.
136 | if (is_asan) {
137 | libs = [ "c++_shared" ]
138 | } else {
139 | libs = [ "c++_static" ]
140 | }
141 | libs += [
142 | "c++abi",
143 | "android_support",
144 | ]
145 |
146 | # arm builds of libc++ starting in NDK r12 depend on unwind.
147 | if (current_cpu == "arm") {
148 | libs += [ "unwind" ]
149 | }
150 |
151 | # Manually link the libgcc.a that the cross compiler uses. This is
152 | # absolute because the linker will look inside the sysroot if it's not.
153 | libs += [
154 | rebase_path(android_libgcc_file),
155 | "c",
156 | ]
157 |
158 | # Clang with libc++ does not require an explicit atomic library reference.
159 | if (!is_clang) {
160 | libs += [ "atomic" ]
161 | }
162 |
163 | if (is_clang) {
164 | # Work around incompatibilities between bionic and clang headers.
165 | defines += [
166 | "__compiler_offsetof=__builtin_offsetof",
167 | "nan=__builtin_nan",
168 | ]
169 |
170 | if (current_cpu == "x64" || current_cpu == "arm64" ||
171 | current_cpu == "mips64el") {
172 | # 64-bit targets build with NDK 21, 32-bit targets with NDK 16
173 | # (see ./config.gni). When using clang, NDK 21 defines snprintf to
174 | # something for a kind of for of _FORTIFY_SOURCE support, see
175 | # third_party/android_tools/ndk/platforms/android-21/arch-x86_64/usr/include/stdio.h
176 | # Making snprintf a macro breaks base/strings/string_utils.h which
177 | # defines base::snprintf(). So define snprintf to itself to force the
178 | # NDK to not redefine it. This disables _chk for snprintf, but since
179 | # 32-bit versions use NDK 16 which doesn't have any fortify support, that
180 | # seems ok. b/32067310 tracks better fortify support with clang.
181 | # TODO(thakis): Remove this once b/32067310 is fixed.
182 | defines += [ "snprintf=snprintf" ]
183 | }
184 | }
185 |
186 | # TODO(jdduke) Re-enable on mips after resolving linking
187 | # issues with libc++ (crbug.com/456380).
188 | if (current_cpu != "mipsel" && current_cpu != "mips64el") {
189 | ldflags += [ "-Wl,--warn-shared-textrel" ]
190 | }
191 | }
192 |
193 | config("executable_config") {
194 | cflags = [ "-fPIE" ]
195 | asmflags = [ "-fPIE" ]
196 | ldflags = [ "-pie" ]
197 | }
198 |
199 | # Instrumentation -------------------------------------------------------------
200 | #
201 | # The BUILDCONFIG file sets the "default_cygprofile_instrumentation" config on
202 | # targets by default. You can override whether the cygprofile instrumentation is
203 | # used on a per-target basis:
204 | #
205 | # configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
206 | # configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
207 |
208 | config("default_cygprofile_instrumentation") {
209 | if (use_order_profiling) {
210 | configs = [ ":cygprofile_instrumentation" ]
211 | } else {
212 | configs = [ ":no_cygprofile_instrumentation" ]
213 | }
214 | }
215 |
216 | config("cygprofile_instrumentation") {
217 | defines = [ "CYGPROFILE_INSTRUMENTATION=1" ]
218 | cflags = [ "-finstrument-functions" ]
219 |
220 | if (!is_clang) {
221 | cflags += [
222 | # Allow mmx intrinsics to inline, so that the compiler can expand the intrinsics.
223 | "-finstrument-functions-exclude-file-list=mmintrin.h",
224 |
225 | # Avoid errors with current NDK:
226 | # "third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/include/arm_neon.h:3426:3: error: argument must be a constant"
227 | "-finstrument-functions-exclude-file-list=arm_neon.h",
228 | ]
229 | }
230 | }
231 |
232 | config("no_cygprofile_instrumentation") {
233 | }
234 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # //build directory for GN-based projects
2 |
3 | This project provides a work-in-progress standalone version of the toolchains and configs used by the Chromium project.
4 |
5 | ## Supported platforms
6 |
7 | The toolchains have been tested on the following platforms:
8 |
9 | * Windows (MSVC 2013/2015/2017/2019/2022, Clang 3.8 - 17.0)
10 | * FreeBSD (GCC 6, Clang 11)
11 | * Linux (GCC 6, Clang 3.8)
12 | * OS X (Xcode 7.3.1)
13 |
14 | The [testsrc](https://github.com/timniederhausen/gn-build/tree/testsrc)
15 | branch contains the test/example project used by the CI tests.
16 |
17 | ## Reference
18 |
19 | ### Basic variables
20 |
21 | All variables described here are build args and can be overridden in the user's
22 | `args.gn` file.
23 |
24 | #### [`//build/config/BUILDCONFIG.gn`](config/BUILDCONFIG.gn)
25 |
26 | (these variables are available everywhere)
27 |
28 | * `is_debug` (default: true): Toggle between debug and release builds.
29 | * `is_clang` (default: false): Favor Clang over the platform default (GCC/MSVC).
30 | * `is_official_build` (default: !is_debug): Set to enable the official build
31 | level of optimization. This enables an additional level of optimization above
32 | release (!is_debug).
33 | * `external` (default: "//external"): Label of the external projects directory.
34 | By convention, all 3rd-party projects should end up in this directory, so they
35 | can depend on each other (e.g. $external/mysql_connector -> $external/zlib)
36 |
37 | #### [`//build/toolchain/clang.gni`](toolchain/clang.gni)
38 |
39 | * `use_lld` (default: false): Use the new LLD linker.
40 | This requires `is_clang` to be true.
41 | * `clang_base_path` (default: ""): The path of your Clang installation folder
42 | (without /bin). If you use Clang on Windows, you are required to set this,
43 | as the Clang installation isn't automatically detected.
44 |
45 | #### [`//build/toolchain/compiler_version.gni`](toolchain/compiler_version.gni)
46 |
47 | * `gcc_version` (default: auto-detected): Version of the GCC compiler.
48 | **Note:** Auto-detection is toolchain-specific and happens only if GCC is the
49 | active compiler.
50 | Format: `major` * 10000 + `minor` * 100 + `patchlevel`
51 | * `clang_version` (default: auto-detected): Version of the Clang compiler.
52 | **Note:** Auto-detection is toolchain-specific and happens only if Clang is
53 | the active compiler.
54 | Format: `major` * 10000 + `minor` * 100 + `patchlevel`
55 | * `msc_ver` (default: auto-detected): Value of the _MSC_VER variable.
56 | See https://msdn.microsoft.com/en-us/library/b0084kay.aspx.
57 | **Note:** Auto-detection happens only when targeting Windows.
58 | * `msc_full_ver` (default: auto-detected): Value of the _MSC_FULL_VER variable.
59 | See https://msdn.microsoft.com/en-us/library/b0084kay.aspx.
60 | **Note:** Auto-detection happens only when targeting Windows.
61 |
62 | ### Windows toolchain
63 |
64 | #### [`//build/toolchain/win/settings.gni`](toolchain/win/settings.gni)
65 |
66 | * `visual_studio_version` (default: "latest"): Desired version of Visual Studio.
67 | If `visual_studio_path` is set, this must be the version of the VS installation
68 | at the `visual_studio_path`.
69 |
70 | Use "2013" for Visual Studio 2013 or "latest" for automatically choosing the
71 | highest version (`visual_studio_path` must be unset in this case).
72 | * `visual_studio_path` (default: auto-detected): The path of your MSVC installation.
73 | If this is set you must set visual_studio_version as well.
74 | Autodetected based on `visual_studio_version`.
75 | * `windows_sdk_version` (default: auto-detected): Windows SDK version to use.
76 | Can either be a full Windows 10 SDK number (e.g. 10.0.10240.0),
77 | "8.1" for the Windows 8.1 SDK or "default" for the default SDK selected by VS.
78 | * `clang_msc_ver` (default: auto-detected): MSVC version `clang-cl` will report
79 | in `_MSC_VER`.
80 |
81 | ### POSIX toolchain
82 |
83 | This is the default toolchain for POSIX operating systems,
84 | which is used for all POSIX systems that don't have special toolchains.
85 |
86 | #### [`//build/toolchain/posix/settings.gni`](toolchain/posix/settings.gni)
87 |
88 | * `gcc_cc` (default: gcc): Path of the GCC C compiler executable.
89 | Does not have to be absolute.
90 | * `gcc_cxx` (default: g++): Path of the GCC C++ compiler executable.
91 | Does not have to be absolute.
92 | * `clang_cc` (default: clang): Path of the Clang C compiler executable.
93 | Does not have to be absolute. **Note:** If `clang_base_path` is set,
94 | the default will be `clang_base_path/bin/clang`.
95 | * `clang_cxx` (default: clang++): Path of the Clang C++ compiler executable.
96 | Does not have to be absolute. **Note:** If `clang_base_path` is set,
97 | the default will be `clang_base_path/bin/clang++`.
98 |
99 | ### Mac/iOS toolchain
100 |
101 | #### [`//build/toolchain/mac/settings.gni`](toolchain/mac/settings.gni)
102 |
103 | * `use_system_xcode` (default: true): Use the system install of Xcode for tools
104 | like ibtool, libtool, etc. This does not affect the compiler. When this
105 | variable is false, targets will instead use a hermetic install of Xcode.
106 | * `hermetic_xcode_path` (default: ""): The path to the hermetic install of
107 | Xcode. Only relevant when use_system_xcode = false.
108 | * `use_xcode_clang` (default: true): Compile with Xcode version of clang
109 | instead of hermetic version shipped with the build. If `true`,
110 | `clang_base_path` needs to be set.
111 | * `enable_dsyms` (default: true): Produce dSYM files for targets that are
112 | configured to do so. dSYM generation is controlled globally as it is a
113 | linker output (produced via the `//build/toolchain/mac/linker_driver.py`.
114 | Enabling this will result in all shared library, loadable module, and
115 | executable targets having a dSYM generated.
116 | * `enable_stripping` (default: `is_official_build`): Strip symbols from linked
117 | targets by default. If this is enabled, the //build/config/mac:strip_all
118 | config will be applied to all linked targets. If custom stripping parameters
119 | are required, remove that config from a linked target and apply custom
120 | `-Wcrl,strip` flags. See //build/toolchain/mac/linker_driver.py for more
121 | information.
122 |
123 | #### [`//build/toolchain/mac/mac_sdk.gni`](toolchain/mac/mac_sdk.gni)
124 |
125 | * `mac_sdk_min` (default: "10.10"): Minimum supported version of the Mac SDK.
126 | * `mac_deployment_target` (default: "10.9"): Minimum supported version of OSX.
127 | * `mac_sdk_path` (default: ""): Path to a specific version of the Mac SDK, not
128 | including a slash at the end. If empty, the path to the lowest version
129 | greater than or equal to `mac_sdk_min` is used.
130 | * `mac_sdk_name` (default: "macosx"): The SDK name as accepted by xcodebuild.
131 |
132 | #### [`//build/toolchain/mac/ios_sdk.gni`](toolchain/mac/ios_sdk.gni)
133 |
134 | * `ios_sdk_path` (default: ""): Path to a specific version of the iOS SDK, not
135 | including a slash at the end. When empty this will use the default SDK based
136 | on the value of use_ios_simulator.
137 |
138 | SDK properties (required when `ios_sdk_path` is non-empty):
139 |
140 | * `ios_sdk_name`: The SDK name as accepted by xcodebuild.
141 | * `ios_sdk_version`
142 | * `ios_sdk_platform`
143 | * `ios_sdk_platform_path`
144 | * `xcode_version`
145 | * `xcode_build`
146 | * `machine_os_build`
147 |
148 | * `ios_deployment_target` (default: "9.0"): Minimum supported version of OSX.
149 |
150 | ### Android toolchain
151 |
152 | #### [`//build/toolchain/android/settings.gni`](toolchain/android/settings.gni)
153 |
154 | * `android_ndk_root` (default: "$external/android_tools/ndk"):
155 | Path of the Android NDK.
156 | * `android_ndk_version` (default: "r12b"): NDK Version string.
157 | * `android_ndk_major_version` (default: 12): NDK Major version.
158 | * `android_sdk_root` (default: "$external/android_tools/sdk"):
159 | Path of the Android SDK.
160 | * `android_sdk_version` (default: "24"): Android SDK version.
161 | * `android_sdk_build_tools_version` (default: "24.0.2"):
162 | Version of the Build Tools contained in the SDK.
163 | * `android_libcpp_lib_dir` (default: ""): Libc++ library directory.
164 | Override to use a custom libc++ binary.
165 | * `use_order_profiling` (default: false): Adds intrumentation to each function.
166 | Writes a file with the order that functions are called at startup.
167 |
168 | ## Recommended workflow
169 |
170 | Fork this repo and add it as a submodule/subtree/`DEPS`-entry to your project.
171 | This way you can modify every part of the `//build` directory while still being
172 | able to easily merge upstream changes (e.g. support for new GN features that
173 | you don't want to implement yourself.)
174 |
175 | To ease sharing/composition of projects using this `//build` repo,
176 | it is recommended that you refrain from modifying large parts of the toolchains/configs.
177 | If changes are necessary, consider contributing them back ;)
178 |
179 | For more complex projects, it might be feasible to use a custom build-config file
180 | that just `import()s` [`//build/config/BUILDCONFIG.gn`](config/BUILDCONFIG.gn) and then overrides
181 | the defaults set inside `BUILDCONFIG.gn`. There's also GN's `default_args` scope, which can be used
182 | to provide project-specific argument overrides.
183 |
--------------------------------------------------------------------------------
/toolchain/android/settings.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2014 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | # This file contains common system config stuff for the Android build.
6 |
7 | declare_args() {
8 | android_ndk_root = "$external/android_tools/ndk"
9 | android_ndk_version = "r12b"
10 | android_ndk_major_version = 12
11 |
12 | android_sdk_root = "$external/android_tools/sdk"
13 | android_sdk_version = "24"
14 | android_sdk_build_tools_version = "24.0.2"
15 |
16 | lint_android_sdk_root = "$external/android_tools/sdk"
17 | lint_android_sdk_version = "24"
18 |
19 | # Libc++ library directory. Override to use a custom libc++ binary.
20 | android_libcpp_lib_dir = ""
21 |
22 | # Adds intrumentation to each function. Writes a file with the order that
23 | # functions are called at startup.
24 | use_order_profiling = false
25 | }
26 |
27 | # Host stuff -----------------------------------------------------------------
28 |
29 | # Defines the name the Android build gives to the current host CPU
30 | # architecture, which is different than the names GN uses.
31 | if (host_cpu == "x64") {
32 | android_host_arch = "x86_64"
33 | } else if (host_cpu == "x86") {
34 | android_host_arch = "x86"
35 | } else {
36 | assert(false, "Need Android toolchain support for your build CPU arch.")
37 | }
38 |
39 | # Defines the name the Android build gives to the current host CPU
40 | # architecture, which is different than the names GN uses.
41 | if (host_os == "linux") {
42 | android_host_os = "linux"
43 | } else if (host_os == "mac") {
44 | android_host_os = "darwin"
45 | } else if (host_os == "win") {
46 | android_host_os = "windows"
47 | } else {
48 | assert(false, "Need Android toolchain support for your build OS.")
49 | }
50 |
51 | # Directories and files ------------------------------------------------------
52 | #
53 | # We define may of the dirs strings here for each output architecture (rather
54 | # than just the current one) since these are needed by the Android toolchain
55 | # file to define toolchains for all possible targets in one pass.
56 |
57 | android_sdk = "${android_sdk_root}/platforms/android-${android_sdk_version}"
58 |
59 | # Path to the Android NDK and SDK.
60 | android_ndk_include_dir = "$android_ndk_root/usr/include"
61 |
62 | android_sdk_tools = "${android_sdk_root}/tools"
63 | android_sdk_build_tools =
64 | "${android_sdk_root}/build-tools/$android_sdk_build_tools_version"
65 |
66 | # Path to the SDK's android.jar
67 | android_sdk_jar = "$android_sdk/android.jar"
68 |
69 | zipalign_path = "$android_sdk_build_tools/zipalign"
70 |
71 | # Subdirectories inside android_ndk_root that contain the sysroot for the
72 | # associated platform.
73 | # If you raise this, reevaluate the snprintf=snprintf in ./BUILD.gn.
74 | _android_api_level = 16
75 | x86_android_sysroot_subdir = "platforms/android-${_android_api_level}/arch-x86"
76 | arm_android_sysroot_subdir = "platforms/android-${_android_api_level}/arch-arm"
77 | mips_android_sysroot_subdir =
78 | "platforms/android-${_android_api_level}/arch-mips"
79 |
80 | # If you raise this, reevaluate the snprintf=snprintf in ./BUILD.gn.
81 | _android64_api_level = 21
82 | x86_64_android_sysroot_subdir =
83 | "platforms/android-${_android64_api_level}/arch-x86_64"
84 | arm64_android_sysroot_subdir =
85 | "platforms/android-${_android64_api_level}/arch-arm64"
86 | mips64_android_sysroot_subdir =
87 | "platforms/android-${_android64_api_level}/arch-mips64"
88 |
89 | # Toolchain root directory for each build. The actual binaries are inside
90 | # a "bin" directory inside of these.
91 | _android_toolchain_version = "4.9"
92 | _android_toolchain_detailed_version = "4.9.x"
93 | x86_android_toolchain_root = "$android_ndk_root/toolchains/x86-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
94 | arm_android_toolchain_root = "$android_ndk_root/toolchains/arm-linux-androideabi-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
95 | mips_android_toolchain_root = "$android_ndk_root/toolchains/mipsel-linux-android-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
96 | x86_64_android_toolchain_root = "$android_ndk_root/toolchains/x86_64-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
97 | arm64_android_toolchain_root = "$android_ndk_root/toolchains/aarch64-linux-android-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
98 | mips64_android_toolchain_root = "$android_ndk_root/toolchains/mips64el-linux-android-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
99 |
100 | # Location of libgcc. This is only needed for the current GN toolchain, so we
101 | # only need to define the current one, rather than one for every platform
102 | # like the toolchain roots.
103 | if (current_cpu == "x86") {
104 | android_prebuilt_arch = "android-x86"
105 | _binary_prefix = "i686-linux-android"
106 | android_toolchain_root = "$x86_android_toolchain_root"
107 | android_libgcc_file = "$android_toolchain_root/lib/gcc/i686-linux-android/${_android_toolchain_detailed_version}/libgcc.a"
108 | } else if (current_cpu == "arm") {
109 | android_prebuilt_arch = "android-arm"
110 | _binary_prefix = "arm-linux-androideabi"
111 | android_toolchain_root = "$arm_android_toolchain_root"
112 | android_libgcc_file = "$android_toolchain_root/lib/gcc/arm-linux-androideabi/${_android_toolchain_detailed_version}/libgcc.a"
113 | } else if (current_cpu == "mipsel") {
114 | android_prebuilt_arch = "android-mips"
115 | _binary_prefix = "mipsel-linux-android"
116 | android_toolchain_root = "$mips_android_toolchain_root"
117 | android_libgcc_file = "$android_toolchain_root/lib/gcc/mipsel-linux-android/${_android_toolchain_detailed_version}/libgcc.a"
118 | } else if (current_cpu == "x64") {
119 | android_prebuilt_arch = "android-x86_64"
120 | _binary_prefix = "x86_64-linux-android"
121 | android_toolchain_root = "$x86_64_android_toolchain_root"
122 | android_libgcc_file = "$android_toolchain_root/lib/gcc/x86_64-linux-android/${_android_toolchain_detailed_version}/libgcc.a"
123 | } else if (current_cpu == "arm64") {
124 | android_prebuilt_arch = "android-arm64"
125 | _binary_prefix = "aarch64-linux-android"
126 | android_toolchain_root = "$arm64_android_toolchain_root"
127 | android_libgcc_file = "$android_toolchain_root/lib/gcc/aarch64-linux-android/${_android_toolchain_detailed_version}/libgcc.a"
128 | } else if (current_cpu == "mips64el") {
129 | android_prebuilt_arch = "android-mips64"
130 | _binary_prefix = "mips64el-linux-android"
131 | android_toolchain_root = "$mips64_android_toolchain_root"
132 | android_libgcc_file = "$android_toolchain_root/lib/gcc/mips64el-linux-android/${_android_toolchain_detailed_version}/libgcc.a"
133 | } else {
134 | assert(false, "Need android libgcc support for your target arch.")
135 | }
136 |
137 | android_tool_prefix = "$android_toolchain_root/bin/$_binary_prefix-"
138 | android_readelf = "${android_tool_prefix}readelf"
139 | android_objcopy = "${android_tool_prefix}objcopy"
140 | android_gdbserver =
141 | "$android_ndk_root/prebuilt/$android_prebuilt_arch/gdbserver/gdbserver"
142 |
143 | # Toolchain stuff ------------------------------------------------------------
144 |
145 | android_libcpp_root = "$android_ndk_root/sources/cxx-stl/llvm-libc++"
146 |
147 | # ABI ------------------------------------------------------------------------
148 |
149 | if (current_cpu == "x86") {
150 | android_app_abi = "x86"
151 | } else if (current_cpu == "arm") {
152 | import("//build/config/arm.gni")
153 | if (arm_version < 7) {
154 | android_app_abi = "armeabi"
155 | } else {
156 | android_app_abi = "armeabi-v7a"
157 | }
158 | } else if (current_cpu == "mipsel") {
159 | android_app_abi = "mips"
160 | } else if (current_cpu == "x64") {
161 | android_app_abi = "x86_64"
162 | } else if (current_cpu == "arm64") {
163 | android_app_abi = "arm64-v8a"
164 | } else if (current_cpu == "mips64el") {
165 | android_app_abi = "mips64"
166 | } else {
167 | assert(false, "Unknown Android ABI: " + current_cpu)
168 | }
169 |
170 | if (android_libcpp_lib_dir == "") {
171 | android_libcpp_lib_dir = "${android_libcpp_root}/libs/${android_app_abi}"
172 | }
173 |
174 | # Secondary ABI -------------------------------------------------------------
175 | if (target_cpu == "arm64" || target_cpu == "x64" || target_cpu == "mips64el") {
176 | android_64bit_target_cpu = true
177 | } else if (target_cpu == "arm" || target_cpu == "x86" ||
178 | target_cpu == "mipsel") {
179 | android_64bit_target_cpu = false
180 | } else {
181 | assert(false, "Unknown target CPU: $target_cpu")
182 | }
183 |
184 | # Intentionally do not define android_app_secondary_abi_cpu and
185 | # android_app_secondary_abi for 32-bit target_cpu, since they are not used.
186 | if (target_cpu == "arm64") {
187 | android_secondary_abi_cpu = "arm"
188 | android_app_secondary_abi = "armeabi-v7a"
189 | } else if (target_cpu == "x64") {
190 | android_secondary_abi_cpu = "x86"
191 | android_app_secondary_abi = "x86"
192 | } else if (target_cpu == "mips64el") {
193 | android_secondary_abi_cpu = "mipsel"
194 | android_app_secondary_abi = "mips"
195 | }
196 |
197 | if (defined(android_secondary_abi_cpu)) {
198 | if (is_clang) {
199 | android_secondary_abi_toolchain =
200 | "//build/toolchain/android:android_clang_${android_secondary_abi_cpu}"
201 | } else {
202 | android_secondary_abi_toolchain =
203 | "//build/toolchain/android:android_${android_secondary_abi_cpu}"
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/apple/plist_util.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import argparse
6 | import codecs
7 | import plistlib
8 | import os
9 | import re
10 | import subprocess
11 | import sys
12 | import tempfile
13 | import shlex
14 |
15 | if sys.version_info.major < 3:
16 | basestring_compat = basestring
17 | else:
18 | basestring_compat = str
19 |
20 | # Xcode substitutes variables like ${PRODUCT_NAME} or $(PRODUCT_NAME) when
21 | # compiling Info.plist. It also supports supports modifiers like :identifier
22 | # or :rfc1034identifier. SUBSTITUTION_REGEXP_LIST is a list of regular
23 | # expressions matching a variable substitution pattern with an optional
24 | # modifier, while INVALID_CHARACTER_REGEXP matches all characters that are
25 | # not valid in an "identifier" value (used when applying the modifier).
26 | INVALID_CHARACTER_REGEXP = re.compile(r'[_/\s]')
27 | SUBSTITUTION_REGEXP_LIST = (
28 | re.compile(r'\$\{(?P[^}]*?)(?P:[^}]*)?\}'),
29 | re.compile(r'\$\((?P[^}]*?)(?P:[^}]*)?\)'),
30 | )
31 |
32 |
33 | class SubstitutionError(Exception):
34 | def __init__(self, key):
35 | super(SubstitutionError, self).__init__()
36 | self.key = key
37 |
38 | def __str__(self):
39 | return "SubstitutionError: {}".format(self.key)
40 |
41 |
42 | def InterpolateString(value, substitutions):
43 | """Interpolates variable references into |value| using |substitutions|.
44 |
45 | Inputs:
46 | value: a string
47 | substitutions: a mapping of variable names to values
48 |
49 | Returns:
50 | A new string with all variables references ${VARIABLES} replaced by their
51 | value in |substitutions|. Raises SubstitutionError if a variable has no
52 | substitution.
53 | """
54 |
55 | def repl(match):
56 | variable = match.group('id')
57 | if variable not in substitutions:
58 | raise SubstitutionError(variable)
59 | # Some values need to be identifier and thus the variables references may
60 | # contains :modifier attributes to indicate how they should be converted
61 | # to identifiers ("identifier" replaces all invalid characters by '_' and
62 | # "rfc1034identifier" replaces them by "-" to make valid URI too).
63 | modifier = match.group('modifier')
64 | if modifier == ':identifier':
65 | return INVALID_CHARACTER_REGEXP.sub('_', substitutions[variable])
66 | elif modifier == ':rfc1034identifier':
67 | return INVALID_CHARACTER_REGEXP.sub('-', substitutions[variable])
68 | else:
69 | return substitutions[variable]
70 |
71 | for substitution_regexp in SUBSTITUTION_REGEXP_LIST:
72 | value = substitution_regexp.sub(repl, value)
73 | return value
74 |
75 |
76 | def Interpolate(value, substitutions):
77 | """Interpolates variable references into |value| using |substitutions|.
78 |
79 | Inputs:
80 | value: a value, can be a dictionary, list, string or other
81 | substitutions: a mapping of variable names to values
82 |
83 | Returns:
84 | A new value with all variables references ${VARIABLES} replaced by their
85 | value in |substitutions|. Raises SubstitutionError if a variable has no
86 | substitution.
87 | """
88 | if isinstance(value, dict):
89 | return {k: Interpolate(v, substitutions) for k, v in value.items()}
90 | if isinstance(value, list):
91 | return [Interpolate(v, substitutions) for v in value]
92 | if isinstance(value, basestring_compat):
93 | return InterpolateString(value, substitutions)
94 | return value
95 |
96 |
97 | def LoadPList(path):
98 | """Loads Plist at |path| and returns it as a dictionary."""
99 | if sys.version_info.major == 2:
100 | fd, name = tempfile.mkstemp()
101 | try:
102 | subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path])
103 | with os.fdopen(fd, 'rb') as f:
104 | return plistlib.readPlist(f)
105 | finally:
106 | os.unlink(name)
107 | else:
108 | with open(path, 'rb') as f:
109 | return plistlib.load(f)
110 |
111 |
112 | def SavePList(path, format, data):
113 | """Saves |data| as a Plist to |path| in the specified |format|."""
114 | # The below does not replace the destination file but update it in place,
115 | # so if more than one hardlink points to destination all of them will be
116 | # modified. This is not what is expected, so delete destination file if
117 | # it does exist.
118 | if os.path.exists(path):
119 | os.unlink(path)
120 | if sys.version_info.major == 2:
121 | fd, name = tempfile.mkstemp()
122 | try:
123 | with os.fdopen(fd, 'wb') as f:
124 | plistlib.writePlist(data, f)
125 | subprocess.check_call(['plutil', '-convert', format, '-o', path, name])
126 | finally:
127 | os.unlink(name)
128 | else:
129 | with open(path, 'wb') as f:
130 | plist_format = {'binary1': plistlib.FMT_BINARY, 'xml1': plistlib.FMT_XML}
131 | plistlib.dump(data, f, fmt=plist_format[format])
132 |
133 |
134 | def MergePList(plist1, plist2):
135 | """Merges |plist1| with |plist2| recursively.
136 |
137 | Creates a new dictionary representing a Property List (.plist) files by
138 | merging the two dictionary |plist1| and |plist2| recursively (only for
139 | dictionary values). List value will be concatenated.
140 |
141 | Args:
142 | plist1: a dictionary representing a Property List (.plist) file
143 | plist2: a dictionary representing a Property List (.plist) file
144 |
145 | Returns:
146 | A new dictionary representing a Property List (.plist) file by merging
147 | |plist1| with |plist2|. If any value is a dictionary, they are merged
148 | recursively, otherwise |plist2| value is used. If values are list, they
149 | are concatenated.
150 | """
151 | result = plist1.copy()
152 | for key, value in plist2.items():
153 | if isinstance(value, dict):
154 | old_value = result.get(key)
155 | if isinstance(old_value, dict):
156 | value = MergePList(old_value, value)
157 | if isinstance(value, list):
158 | value = plist1.get(key, []) + plist2.get(key, [])
159 | result[key] = value
160 | return result
161 |
162 |
163 | class Action(object):
164 | """Class implementing one action supported by the script."""
165 |
166 | @classmethod
167 | def Register(cls, subparsers):
168 | parser = subparsers.add_parser(cls.name, help=cls.help)
169 | parser.set_defaults(func=cls._Execute)
170 | cls._Register(parser)
171 |
172 |
173 | class MergeAction(Action):
174 | """Class to merge multiple plist files."""
175 |
176 | name = 'merge'
177 | help = 'merge multiple plist files'
178 |
179 | @staticmethod
180 | def _Register(parser):
181 | parser.add_argument('-o',
182 | '--output',
183 | required=True,
184 | help='path to the output plist file')
185 | parser.add_argument('-f',
186 | '--format',
187 | required=True,
188 | choices=('xml1', 'binary1'),
189 | help='format of the plist file to generate')
190 | parser.add_argument(
191 | '-x',
192 | '--xcode-version',
193 | help='version of Xcode, ignored (can be used to force rebuild)')
194 | parser.add_argument('path', nargs="+", help='path to plist files to merge')
195 |
196 | @staticmethod
197 | def _Execute(args):
198 | data = {}
199 | for filename in args.path:
200 | data = MergePList(data, LoadPList(filename))
201 | SavePList(args.output, args.format, data)
202 |
203 |
204 | class SubstituteAction(Action):
205 | """Class implementing the variable substitution in a plist file."""
206 |
207 | name = 'substitute'
208 | help = 'perform pattern substitution in a plist file'
209 |
210 | @staticmethod
211 | def _Register(parser):
212 | parser.add_argument('-o',
213 | '--output',
214 | required=True,
215 | help='path to the output plist file')
216 | parser.add_argument('-t',
217 | '--template',
218 | required=True,
219 | help='path to the template file')
220 | parser.add_argument('-s',
221 | '--substitution',
222 | action='append',
223 | default=[],
224 | help='substitution rule in the format key=value')
225 | parser.add_argument('-f',
226 | '--format',
227 | required=True,
228 | choices=('xml1', 'binary1'),
229 | help='format of the plist file to generate')
230 | parser.add_argument(
231 | '-x',
232 | '--xcode-version',
233 | help='version of Xcode, ignored (can be used to force rebuild)')
234 |
235 | @staticmethod
236 | def _Execute(args):
237 | substitutions = {}
238 | for substitution in args.substitution:
239 | key, value = substitution.split('=', 1)
240 | substitutions[key] = value
241 | data = Interpolate(LoadPList(args.template), substitutions)
242 | SavePList(args.output, args.format, data)
243 |
244 |
245 | def Main():
246 | # Cache this codec so that plistlib can find it. See
247 | # https://crbug.com/1005190#c2 for more details.
248 | codecs.lookup('utf-8')
249 |
250 | parser = argparse.ArgumentParser(description='manipulate plist files')
251 | subparsers = parser.add_subparsers()
252 |
253 | for action in [MergeAction, SubstituteAction]:
254 | action.Register(subparsers)
255 |
256 | args = parser.parse_args()
257 | args.func(args)
258 |
259 |
260 | if __name__ == '__main__':
261 | # TODO(https://crbug.com/941669): Temporary workaround until all scripts use
262 | # python3 by default.
263 | if sys.version_info[0] < 3:
264 | os.execvp('python3', ['python3'] + sys.argv)
265 | sys.exit(Main())
266 |
--------------------------------------------------------------------------------
/config/sanitizers/sanitizers.gni:
--------------------------------------------------------------------------------
1 | # Copyright 2015 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | declare_args() {
6 | # Compile for Address Sanitizer to find memory bugs.
7 | is_asan = false
8 |
9 | # Compile for Hardware-Assisted Address Sanitizer to find memory bugs
10 | # (android/arm64 only).
11 | # See http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
12 | is_hwasan = false
13 |
14 | # Compile for Leak Sanitizer to find leaks.
15 | is_lsan = false
16 |
17 | # Compile for Memory Sanitizer to find uninitialized reads.
18 | is_msan = false
19 |
20 | # Compile for Thread Sanitizer to find threading bugs.
21 | is_tsan = false
22 |
23 | # Compile for Undefined Behaviour Sanitizer to find various types of
24 | # undefined behaviour (excludes vptr checks).
25 | is_ubsan = false
26 |
27 | # Halt the program if a problem is detected.
28 | is_ubsan_no_recover = false
29 |
30 | # Compile for Undefined Behaviour Sanitizer's null pointer checks.
31 | is_ubsan_null = false
32 |
33 | # Track where uninitialized memory originates from. From fastest to slowest:
34 | # 0 - no tracking, 1 - track only the initial allocation site, 2 - track the
35 | # chain of stores leading from allocation site to use site.
36 | msan_track_origins = 2
37 |
38 | # Use dynamic libraries instrumented by one of the sanitizers instead of the
39 | # standard system libraries. Set this flag to build the libraries from source.
40 | use_locally_built_instrumented_libraries = false
41 |
42 | # Enable building with SyzyAsan which can find certain types of memory
43 | # errors. Only works on Windows. See
44 | # https://github.com/google/syzygy/wiki/SyzyASanHowTo
45 | is_syzyasan = false
46 |
47 | # Compile with Control Flow Integrity to protect virtual calls and casts.
48 | # See http://clang.llvm.org/docs/ControlFlowIntegrity.html
49 | is_cfi = false
50 |
51 | # Enable checks for indirect function calls via a function pointer.
52 | # TODO(pcc): remove this when we're ready to add these checks by default.
53 | # https://crbug.com/701919
54 | #
55 | # TODO(crbug.com/1159424): Reassess the validity of the next expression.
56 | use_cfi_icall = false
57 |
58 | # Enable checks for bad casts: derived cast and unrelated cast.
59 | # TODO(krasin): remove this, when we're ready to add these checks by default.
60 | # https://crbug.com/626794
61 | use_cfi_cast = false
62 |
63 | # By default, Control Flow Integrity will crash the program if it detects a
64 | # violation. Set this to true to print detailed diagnostics instead.
65 | use_cfi_diag = false
66 |
67 | # Let Control Flow Integrity continue execution instead of crashing when
68 | # printing diagnostics (use_cfi_diag = true).
69 | use_cfi_recover = false
70 |
71 | # Compile for fuzzing with LLVM LibFuzzer.
72 | # See http://www.chromium.org/developers/testing/libfuzzer
73 | use_libfuzzer = false
74 |
75 | # Compile for fuzzing with AFL.
76 | use_afl = false
77 |
78 | # Compile for fuzzing with an external engine (e.g., Grammarinator).
79 | use_external_fuzzing_engine = false
80 |
81 | # Enables core ubsan security features. Will later be removed once it matches
82 | # is_ubsan.
83 | is_ubsan_security = false
84 |
85 | # Compile for fuzzing with Dr. Fuzz
86 | # See http://www.chromium.org/developers/testing/dr-fuzz
87 | use_drfuzz = false
88 |
89 | # Helper variable for testing builds with disabled libfuzzer.
90 | # Not for client use.
91 | disable_libfuzzer = false
92 |
93 | # Value for -fsanitize-coverage flag. Setting this causes
94 | # use_sanitizer_coverage to be enabled.
95 | # This flag is not used for libFuzzer (use_libfuzzer=true). Instead, we use:
96 | # -fsanitize=fuzzer-no-link
97 | # Default value when unset and use_fuzzing_engine=true:
98 | # trace-pc-guard
99 | # Default value when unset and use_sanitizer_coverage=true:
100 | # trace-pc-guard,indirect-calls
101 | sanitizer_coverage_flags = ""
102 |
103 | # When enabled, only relevant sanitizer defines are set, but compilation
104 | # happens with no extra flags. This is useful when in component build
105 | # enabling sanitizers only in some of the components.
106 | use_sanitizer_configs_without_instrumentation = false
107 |
108 | # When true, seed corpora archives are built.
109 | archive_seed_corpus = true
110 | }
111 |
112 | declare_args() {
113 | # Compile for Undefined Behaviour Sanitizer's vptr checks.
114 | is_ubsan_vptr = is_ubsan_security
115 | }
116 |
117 | # Disable sanitizers for non-default toolchains.
118 | if (current_toolchain != default_toolchain) {
119 | is_asan = false
120 | is_cfi = false
121 | is_hwasan = false
122 | is_lsan = false
123 | is_msan = false
124 | is_tsan = false
125 | is_ubsan = false
126 | is_ubsan_null = false
127 | is_ubsan_no_recover = false
128 | is_ubsan_security = false
129 | is_ubsan_vptr = false
130 | msan_track_origins = 0
131 | sanitizer_coverage_flags = ""
132 | use_afl = false
133 | use_cfi_diag = false
134 | use_cfi_recover = false
135 | use_libfuzzer = false
136 | use_locally_built_instrumented_libraries = false
137 | use_sanitizer_coverage = false
138 | }
139 |
140 | # Use dynamic libraries instrumented by one of the sanitizers instead of the
141 | # standard system libraries. We have instrumented system libraries for msan,
142 | # which requires them to prevent false positives.
143 | # TODO(thakis): Maybe remove this variable.
144 | use_prebuilt_instrumented_libraries = is_msan
145 |
146 | # Whether we are doing a fuzzer build. Normally this should be checked instead
147 | # of checking "use_libfuzzer || use_afl" because often developers forget to
148 | # check for "use_afl".
149 | use_fuzzing_engine = use_libfuzzer || use_afl || use_external_fuzzing_engine
150 |
151 | # Args that are in turn dependent on other args must be in a separate
152 | # declare_args block. User overrides are only applied at the end of a
153 | # declare_args block.
154 | declare_args() {
155 | # Enable -fsanitize-coverage.
156 | use_sanitizer_coverage = use_fuzzing_engine || sanitizer_coverage_flags != ""
157 | }
158 |
159 | if (use_fuzzing_engine && sanitizer_coverage_flags == "") {
160 | sanitizer_coverage_flags = "trace-pc-guard"
161 | } else if (use_sanitizer_coverage && sanitizer_coverage_flags == "") {
162 | sanitizer_coverage_flags = "trace-pc-guard,indirect-calls"
163 | }
164 |
165 | # Whether we are linking against a sanitizer runtime library. Among other
166 | # things, this changes the default symbol level and other settings in order to
167 | # prepare to create stack traces "live" using the sanitizer runtime.
168 | using_sanitizer = is_asan || is_hwasan || is_lsan || is_tsan || is_msan ||
169 | is_ubsan || is_ubsan_null || is_ubsan_vptr ||
170 | is_ubsan_security || use_sanitizer_coverage || use_cfi_diag
171 |
172 | assert(!using_sanitizer || is_clang,
173 | "Sanitizers (is_*san) require setting is_clang = true in 'gn args'")
174 |
175 | assert(!is_cfi || is_clang,
176 | "is_cfi requires setting is_clang = true in 'gn args'")
177 |
178 | prebuilt_instrumented_libraries_available =
179 | is_msan && (msan_track_origins == 0 || msan_track_origins == 2)
180 |
181 | if (use_libfuzzer && (is_linux || is_chromeos)) {
182 | if (is_asan) {
183 | # We do leak checking with libFuzzer on Linux. Set is_lsan for code that
184 | # relies on LEAK_SANITIZER define to avoid false positives.
185 | is_lsan = true
186 | }
187 | }
188 |
189 | # MSan only links Chrome properly in release builds (brettw -- 9/1/2015). The
190 | # same is possibly true for the other non-ASan sanitizers. But regardless of
191 | # whether it links, one would normally never run a sanitizer in debug mode.
192 | # Running in debug mode probably indicates you forgot to set the "is_debug =
193 | # false" flag in the build args. ASan seems to run fine in debug mode.
194 | #
195 | # If you find a use-case where you want to compile a sanitizer in debug mode
196 | # and have verified it works, ask brettw and we can consider removing it from
197 | # this condition. We may also be able to find another way to enable your case
198 | # without having people accidentally get broken builds by compiling an
199 | # unsupported or unadvisable configurations.
200 | #
201 | # For one-off testing, just comment this assertion out.
202 | assert(!is_debug || !(is_msan || is_ubsan || is_ubsan_null || is_ubsan_vptr),
203 | "Sanitizers should generally be used in release (set is_debug=false).")
204 |
205 | assert(!is_hwasan || (is_android && current_cpu == "arm64"),
206 | "HWASan only supported on Android ARM64 builds.")
207 |
208 | assert(!is_msan || ((is_linux || is_chromeos) && current_cpu == "x64"),
209 | "MSan currently only works on 64-bit Linux and ChromeOS builds.")
210 |
211 | assert(!is_lsan || is_asan, "is_lsan = true requires is_asan = true also.")
212 |
213 | # ASAN build on Windows is not working in debug mode. Intercepting memory
214 | # allocation functions is hard on Windows and not yet implemented in LLVM.
215 | assert(!is_win || !is_debug || !is_asan,
216 | "ASan on Windows doesn't work in debug (set is_debug=false).")
217 |
218 | # libFuzzer targets can fail to build or behave incorrectly when built without
219 | # ASAN on Windows.
220 | assert(!is_win || !use_libfuzzer || is_asan,
221 | "use_libfuzzer on Windows requires setting is_asan = true")
222 |
223 | # Make sure that if we recover on detection (i.e. not crash), diagnostics are
224 | # printed.
225 | assert(!use_cfi_recover || use_cfi_diag,
226 | "Only use CFI recovery together with diagnostics.")
227 |
228 | # TODO(crbug.com/753445): the use_sanitizer_coverage arg is currently
229 | # not supported by the Chromium mac_clang_x64 toolchain on iOS distribution.
230 | # The coverage works with iOS toolchain but it is broken when the mac
231 | # toolchain is used as a secondary one on iOS distribution. E.g., it should be
232 | # possible to build the "net" target for iOS with the sanitizer coverage
233 | # enabled.
234 | assert(
235 | !(use_sanitizer_coverage && is_mac && target_os == "ios"),
236 | "crbug.com/753445: use_sanitizer_coverage=true is not supported by the " +
237 | "Chromium mac_clang_x64 toolchain on iOS distribution. Please set " +
238 | "the argument value to false.")
239 |
--------------------------------------------------------------------------------
/toolchain/apple/linker_driver.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2016 The Chromium Authors. All rights reserved.
4 | # Use of this source code is governed by a BSD-style license that can be
5 | # found in the LICENSE file.
6 |
7 | import os
8 | import os.path
9 | import shutil
10 | import subprocess
11 | import sys
12 |
13 | # On mac, the values of these globals are modified when parsing -Wcrl, flags. On
14 | # ios, the script uses the defaults.
15 | DSYMUTIL_INVOKE = ['xcrun', 'dsymutil']
16 | STRIP_INVOKE = ['xcrun', 'strip']
17 |
18 | # Setting this flag will emit a deterministic binary by stripping dates from the
19 | # N_OSO field.
20 | DETERMINISTIC_FLAG = '--deterministic'
21 |
22 | # The linker_driver.py is responsible for forwarding a linker invocation to
23 | # the compiler driver, while processing special arguments itself.
24 | #
25 | # Usage: linker_driver.py clang++ main.o -L. -llib -o prog -Wcrl,dsym,out
26 | #
27 | # On Mac, the logical step of linking is handled by three discrete tools to
28 | # perform the image link, debug info link, and strip. The linker_driver.py
29 | # combines these three steps into a single tool.
30 | #
31 | # The command passed to the linker_driver.py should be the compiler driver
32 | # invocation for the linker. It is first invoked unaltered (except for the
33 | # removal of the special driver arguments, described below). Then the driver
34 | # performs additional actions, based on these arguments:
35 | #
36 | # -Wcrl,dsym,
37 | # After invoking the linker, this will run `dsymutil` on the linker's
38 | # output, producing a dSYM bundle, stored at dsym_path_prefix. As an
39 | # example, if the linker driver were invoked with:
40 | # "... -o out/gn/obj/foo/libbar.dylib ... -Wcrl,dsym,out/gn ..."
41 | # The resulting dSYM would be out/gn/libbar.dylib.dSYM/.
42 | #
43 | # -Wcrl,dsymutilpath,
44 | # Sets the path to the dsymutil to run with -Wcrl,dsym, in which case
45 | # `xcrun` is not used to invoke it.
46 | #
47 | # -Wcrl,unstripped,
48 | # After invoking the linker, and before strip, this will save a copy of
49 | # the unstripped linker output in the directory unstripped_path_prefix.
50 | #
51 | # -Wcrl,strip,
52 | # After invoking the linker, and optionally dsymutil, this will run
53 | # the strip command on the linker's output. strip_arguments are
54 | # comma-separated arguments to be passed to the strip command.
55 | #
56 | # -Wcrl,strippath,
57 | # Sets the path to the strip to run with -Wcrl,strip, in which case
58 | # `xcrun` is not used to invoke it.
59 |
60 |
61 | def Main(args):
62 | """Main function for the linker driver. Separates out the arguments for
63 | the main compiler driver and the linker driver, then invokes all the
64 | required tools.
65 |
66 | Args:
67 | args: list of string, Arguments to the script.
68 | """
69 |
70 | if len(args) < 2:
71 | raise RuntimeError("Usage: linker_driver.py [linker-invocation]")
72 |
73 | # Collect arguments to the linker driver (this script) and remove them from
74 | # the arguments being passed to the compiler driver.
75 | linker_driver_actions = {}
76 | compiler_driver_args = []
77 | deterministic = False
78 | for arg in args[1:]:
79 | if arg.startswith(_LINKER_DRIVER_ARG_PREFIX):
80 | # Convert driver actions into a map of name => lambda to invoke.
81 | driver_action = ProcessLinkerDriverArg(arg)
82 | assert driver_action[0] not in linker_driver_actions
83 | linker_driver_actions[driver_action[0]] = driver_action[1]
84 | elif arg == DETERMINISTIC_FLAG:
85 | deterministic = True
86 | else:
87 | compiler_driver_args.append(arg)
88 |
89 | linker_driver_outputs = [_FindLinkerOutput(compiler_driver_args)]
90 |
91 | try:
92 | # Zero the mtime in OSO fields for deterministic builds.
93 | # https://crbug.com/330262.
94 | env = os.environ.copy()
95 | if deterministic:
96 | env['ZERO_AR_DATE'] = '1'
97 | # Run the linker by invoking the compiler driver.
98 | subprocess.check_call(compiler_driver_args, env=env)
99 |
100 | # Run the linker driver actions, in the order specified by the actions list.
101 | for action in _LINKER_DRIVER_ACTIONS:
102 | name = action[0]
103 | if name in linker_driver_actions:
104 | linker_driver_outputs += linker_driver_actions[name](args)
105 | except:
106 | # If a linker driver action failed, remove all the outputs to make the
107 | # build step atomic.
108 | map(_RemovePath, linker_driver_outputs)
109 |
110 | # Re-report the original failure.
111 | raise
112 |
113 |
114 | def ProcessLinkerDriverArg(arg):
115 | """Processes a linker driver argument and returns a tuple containing the
116 | name and unary lambda to invoke for that linker driver action.
117 |
118 | Args:
119 | arg: string, The linker driver argument.
120 |
121 | Returns:
122 | A 2-tuple:
123 | 0: The driver action name, as in _LINKER_DRIVER_ACTIONS.
124 | 1: An 1-ary lambda that takes the full list of arguments passed to
125 | Main(). The lambda should call the linker driver action that
126 | corresponds to the argument and return a list of outputs from the
127 | action.
128 | """
129 | if not arg.startswith(_LINKER_DRIVER_ARG_PREFIX):
130 | raise ValueError('%s is not a linker driver argument' % (arg, ))
131 |
132 | sub_arg = arg[len(_LINKER_DRIVER_ARG_PREFIX):]
133 |
134 | for driver_action in _LINKER_DRIVER_ACTIONS:
135 | (name, action) = driver_action
136 | if sub_arg.startswith(name):
137 | return (name, lambda full_args: action(sub_arg[len(name):], full_args))
138 |
139 | raise ValueError('Unknown linker driver argument: %s' % (arg, ))
140 |
141 |
142 | def RunDsymUtil(dsym_path_prefix, full_args):
143 | """Linker driver action for -Wcrl,dsym,. Invokes dsymutil
144 | on the linker's output and produces a dsym file at |dsym_file| path.
145 |
146 | Args:
147 | dsym_path_prefix: string, The path at which the dsymutil output should be
148 | located.
149 | full_args: list of string, Full argument list for the linker driver.
150 |
151 | Returns:
152 | list of string, Build step outputs.
153 | """
154 | if not len(dsym_path_prefix):
155 | raise ValueError('Unspecified dSYM output file')
156 |
157 | linker_out = _FindLinkerOutput(full_args)
158 | base = os.path.basename(linker_out)
159 | dsym_out = os.path.join(dsym_path_prefix, base + '.dSYM')
160 |
161 | # Remove old dSYMs before invoking dsymutil.
162 | _RemovePath(dsym_out)
163 |
164 | tools_paths = _FindToolsPaths(full_args)
165 | if os.environ.get('PATH'):
166 | tools_paths.append(os.environ['PATH'])
167 | dsymutil_env = os.environ.copy()
168 | dsymutil_env['PATH'] = ':'.join(tools_paths)
169 | subprocess.check_call(DSYMUTIL_INVOKE + ['-o', dsym_out, linker_out],
170 | env=dsymutil_env)
171 | return [dsym_out]
172 |
173 |
174 | def SetDsymutilPath(dsymutil_path, full_args):
175 | """Linker driver action for -Wcrl,dsymutilpath,.
176 |
177 | Sets the invocation command for dsymutil, which allows the caller to specify
178 | an alternate dsymutil. This action is always processed before the RunDsymUtil
179 | action.
180 |
181 | Args:
182 | dsymutil_path: string, The path to the dsymutil binary to run
183 | full_args: list of string, Full argument list for the linker driver.
184 |
185 | Returns:
186 | No output - this step is run purely for its side-effect.
187 | """
188 | global DSYMUTIL_INVOKE
189 | DSYMUTIL_INVOKE = [dsymutil_path]
190 | return []
191 |
192 |
193 | def RunSaveUnstripped(unstripped_path_prefix, full_args):
194 | """Linker driver action for -Wcrl,unstripped,. Copies
195 | the linker output to |unstripped_path_prefix| before stripping.
196 |
197 | Args:
198 | unstripped_path_prefix: string, The path at which the unstripped output
199 | should be located.
200 | full_args: list of string, Full argument list for the linker driver.
201 |
202 | Returns:
203 | list of string, Build step outputs.
204 | """
205 | if not len(unstripped_path_prefix):
206 | raise ValueError('Unspecified unstripped output file')
207 |
208 | linker_out = _FindLinkerOutput(full_args)
209 | base = os.path.basename(linker_out)
210 | unstripped_out = os.path.join(unstripped_path_prefix, base + '.unstripped')
211 |
212 | shutil.copyfile(linker_out, unstripped_out)
213 | return [unstripped_out]
214 |
215 |
216 | def RunStrip(strip_args_string, full_args):
217 | """Linker driver action for -Wcrl,strip,.
218 |
219 | Args:
220 | strip_args_string: string, Comma-separated arguments for `strip`.
221 | full_args: list of string, Full arguments for the linker driver.
222 |
223 | Returns:
224 | list of string, Build step outputs.
225 | """
226 | strip_command = list(STRIP_INVOKE)
227 | if len(strip_args_string) > 0:
228 | strip_command += strip_args_string.split(',')
229 | strip_command.append(_FindLinkerOutput(full_args))
230 | subprocess.check_call(strip_command)
231 | return []
232 |
233 |
234 | def SetStripPath(strip_path, full_args):
235 | """Linker driver action for -Wcrl,strippath,.
236 |
237 | Sets the invocation command for strip, which allows the caller to specify
238 | an alternate strip. This action is always processed before the RunStrip
239 | action.
240 |
241 | Args:
242 | strip_path: string, The path to the strip binary to run
243 | full_args: list of string, Full argument list for the linker driver.
244 |
245 | Returns:
246 | No output - this step is run purely for its side-effect.
247 | """
248 | global STRIP_INVOKE
249 | STRIP_INVOKE = [strip_path]
250 | return []
251 |
252 |
253 | def _FindLinkerOutput(full_args):
254 | """Finds the output of the linker by looking for the output flag in its
255 | argument list. As this is a required linker argument, raises an error if it
256 | cannot be found.
257 | """
258 | # The linker_driver.py script may be used to wrap either the compiler linker
259 | # (uses -o to configure the output) or lipo (uses -output to configure the
260 | # output). Since wrapping the compiler linker is the most likely possibility
261 | # use try/except and fallback to checking for -output if -o is not found.
262 | try:
263 | output_flag_index = full_args.index('-o')
264 | except ValueError:
265 | output_flag_index = full_args.index('-output')
266 | return full_args[output_flag_index + 1]
267 |
268 |
269 | def _FindToolsPaths(full_args):
270 | """Finds all paths where the script should look for additional tools."""
271 | paths = []
272 | for idx, arg in enumerate(full_args):
273 | if arg in ['-B', '--prefix']:
274 | paths.append(full_args[idx + 1])
275 | elif arg.startswith('-B'):
276 | paths.append(arg[2:])
277 | elif arg.startswith('--prefix='):
278 | paths.append(arg[9:])
279 | return paths
280 |
281 |
282 | def _RemovePath(path):
283 | """Removes the file or directory at |path| if it exists."""
284 | if os.path.exists(path):
285 | if os.path.isdir(path):
286 | shutil.rmtree(path)
287 | else:
288 | os.unlink(path)
289 |
290 |
291 | _LINKER_DRIVER_ARG_PREFIX = '-Wcrl,'
292 | """List of linker driver actions. The sort order of this list affects the
293 | order in which the actions are invoked. The first item in the tuple is the
294 | argument's -Wcrl, and the second is the function to invoke.
295 | """
296 | _LINKER_DRIVER_ACTIONS = [
297 | ('dsymutilpath,', SetDsymutilPath),
298 | ('dsym,', RunDsymUtil),
299 | ('unstripped,', RunSaveUnstripped),
300 | ('strippath,', SetStripPath),
301 | ('strip,', RunStrip),
302 | ]
303 |
304 | if __name__ == '__main__':
305 | Main(sys.argv)
306 | sys.exit(0)
307 |
--------------------------------------------------------------------------------
/gn_helpers_unittest.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 The Chromium Authors. All rights reserved.
2 | # Use of this source code is governed by a BSD-style license that can be
3 | # found in the LICENSE file.
4 |
5 | import sys
6 | import textwrap
7 | import unittest
8 |
9 | import gn_helpers
10 |
11 |
12 | class UnitTest(unittest.TestCase):
13 | def test_ToGNString(self):
14 | test_cases = [
15 | (42, '42', '42'), ('foo', '"foo"', '"foo"'), (True, 'true', 'true'),
16 | (False, 'false', 'false'), ('', '""', '""'),
17 | ('\\$"$\\', '"\\\\\\$\\"\\$\\\\"', '"\\\\\\$\\"\\$\\\\"'),
18 | (' \t\r\n', '" $0x09$0x0D$0x0A"', '" $0x09$0x0D$0x0A"'),
19 | (u'\u2713', '"$0xE2$0x9C$0x93"', '"$0xE2$0x9C$0x93"'),
20 | ([], '[ ]', '[]'), ([1], '[ 1 ]', '[\n 1\n]\n'),
21 | ([3, 1, 4, 1], '[ 3, 1, 4, 1 ]', '[\n 3,\n 1,\n 4,\n 1\n]\n'),
22 | (['a', True, 2], '[ "a", true, 2 ]', '[\n "a",\n true,\n 2\n]\n'),
23 | ({
24 | 'single': 'item'
25 | }, 'single = "item"\n', 'single = "item"\n'),
26 | ({
27 | 'kEy': 137,
28 | '_42A_Zaz_': [False, True]
29 | }, '_42A_Zaz_ = [ false, true ]\nkEy = 137\n',
30 | '_42A_Zaz_ = [\n false,\n true\n]\nkEy = 137\n'),
31 | ([1, 'two',
32 | ['"thr,.$\\', True, False, [],
33 | u'(\u2713)']], '[ 1, "two", [ "\\"thr,.\\$\\\\", true, false, ' +
34 | '[ ], "($0xE2$0x9C$0x93)" ] ]', '''[
35 | 1,
36 | "two",
37 | [
38 | "\\"thr,.\\$\\\\",
39 | true,
40 | false,
41 | [],
42 | "($0xE2$0x9C$0x93)"
43 | ]
44 | ]
45 | '''),
46 | ({
47 | 's': 'foo',
48 | 'n': 42,
49 | 'b': True,
50 | 'a': [3, 'x']
51 | }, 'a = [ 3, "x" ]\nb = true\nn = 42\ns = "foo"\n',
52 | 'a = [\n 3,\n "x"\n]\nb = true\nn = 42\ns = "foo"\n'),
53 | (
54 | [[[], [[]]], []],
55 | '[ [ [ ], [ [ ] ] ], [ ] ]',
56 | '[\n [\n [],\n [\n []\n ]\n ],\n []\n]\n',
57 | ),
58 | (
59 | [{
60 | 'a': 1,
61 | 'c': {
62 | 'z': 8
63 | },
64 | 'b': []
65 | }],
66 | '[ { a = 1\nb = [ ]\nc = { z = 8 } } ]\n',
67 | '[\n {\n a = 1\n b = []\n c = {\n' +
68 | ' z = 8\n }\n }\n]\n',
69 | )
70 | ]
71 | for obj, exp_ugly, exp_pretty in test_cases:
72 | out_ugly = gn_helpers.ToGNString(obj)
73 | self.assertEqual(exp_ugly, out_ugly)
74 | out_pretty = gn_helpers.ToGNString(obj, pretty=True)
75 | self.assertEqual(exp_pretty, out_pretty)
76 |
77 | def test_UnescapeGNString(self):
78 | # Backslash followed by a \, $, or " means the folling character without
79 | # the special meaning. Backslash followed by everything else is a literal.
80 | self.assertEqual(
81 | gn_helpers.UnescapeGNString('\\as\\$\\\\asd\\"'),
82 | '\\as$\\asd"')
83 |
84 | def test_FromGNString(self):
85 | self.assertEqual(
86 | gn_helpers.FromGNString('[1, -20, true, false,["as\\"", []]]'),
87 | [ 1, -20, True, False, [ 'as"', [] ] ])
88 |
89 | with self.assertRaises(gn_helpers.GNError):
90 | parser = gn_helpers.GNValueParser('123 456')
91 | parser.Parse()
92 |
93 | def test_ParseBool(self):
94 | parser = gn_helpers.GNValueParser('true')
95 | self.assertEqual(parser.Parse(), True)
96 |
97 | parser = gn_helpers.GNValueParser('false')
98 | self.assertEqual(parser.Parse(), False)
99 |
100 | def test_ParseNumber(self):
101 | parser = gn_helpers.GNValueParser('123')
102 | self.assertEqual(parser.ParseNumber(), 123)
103 |
104 | with self.assertRaises(gn_helpers.GNError):
105 | parser = gn_helpers.GNValueParser('')
106 | parser.ParseNumber()
107 | with self.assertRaises(gn_helpers.GNError):
108 | parser = gn_helpers.GNValueParser('a123')
109 | parser.ParseNumber()
110 |
111 | def test_ParseString(self):
112 | parser = gn_helpers.GNValueParser('"asdf"')
113 | self.assertEqual(parser.ParseString(), 'asdf')
114 |
115 | with self.assertRaises(gn_helpers.GNError):
116 | parser = gn_helpers.GNValueParser('') # Empty.
117 | parser.ParseString()
118 | with self.assertRaises(gn_helpers.GNError):
119 | parser = gn_helpers.GNValueParser('asdf') # Unquoted.
120 | parser.ParseString()
121 | with self.assertRaises(gn_helpers.GNError):
122 | parser = gn_helpers.GNValueParser('"trailing') # Unterminated.
123 | parser.ParseString()
124 |
125 | def test_ParseList(self):
126 | parser = gn_helpers.GNValueParser('[1,]') # Optional end comma OK.
127 | self.assertEqual(parser.ParseList(), [ 1 ])
128 |
129 | with self.assertRaises(gn_helpers.GNError):
130 | parser = gn_helpers.GNValueParser('') # Empty.
131 | parser.ParseList()
132 | with self.assertRaises(gn_helpers.GNError):
133 | parser = gn_helpers.GNValueParser('asdf') # No [].
134 | parser.ParseList()
135 | with self.assertRaises(gn_helpers.GNError):
136 | parser = gn_helpers.GNValueParser('[1, 2') # Unterminated
137 | parser.ParseList()
138 | with self.assertRaises(gn_helpers.GNError):
139 | parser = gn_helpers.GNValueParser('[1 2]') # No separating comma.
140 | parser.ParseList()
141 |
142 | def test_ParseScope(self):
143 | parser = gn_helpers.GNValueParser('{a = 1}')
144 | self.assertEqual(parser.ParseScope(), {'a': 1})
145 |
146 | with self.assertRaises(gn_helpers.GNError):
147 | parser = gn_helpers.GNValueParser('') # Empty.
148 | parser.ParseScope()
149 | with self.assertRaises(gn_helpers.GNError):
150 | parser = gn_helpers.GNValueParser('asdf') # No {}.
151 | parser.ParseScope()
152 | with self.assertRaises(gn_helpers.GNError):
153 | parser = gn_helpers.GNValueParser('{a = 1') # Unterminated.
154 | parser.ParseScope()
155 | with self.assertRaises(gn_helpers.GNError):
156 | parser = gn_helpers.GNValueParser('{"a" = 1}') # Not identifier.
157 | parser.ParseScope()
158 | with self.assertRaises(gn_helpers.GNError):
159 | parser = gn_helpers.GNValueParser('{a = }') # No value.
160 | parser.ParseScope()
161 |
162 | def test_FromGNArgs(self):
163 | # Booleans and numbers should work; whitespace is allowed works.
164 | self.assertEqual(gn_helpers.FromGNArgs('foo = true\nbar = 1\n'),
165 | {'foo': True, 'bar': 1})
166 |
167 | # Whitespace is not required; strings should also work.
168 | self.assertEqual(gn_helpers.FromGNArgs('foo="bar baz"'),
169 | {'foo': 'bar baz'})
170 |
171 | # Comments should work (and be ignored).
172 | gn_args_lines = [
173 | '# Top-level comment.',
174 | 'foo = true',
175 | 'bar = 1 # In-line comment followed by whitespace.',
176 | ' ',
177 | 'baz = false',
178 | ]
179 | self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), {
180 | 'foo': True,
181 | 'bar': 1,
182 | 'baz': False
183 | })
184 |
185 | # Lists should work.
186 | self.assertEqual(gn_helpers.FromGNArgs('foo=[1, 2, 3]'),
187 | {'foo': [1, 2, 3]})
188 |
189 | # Empty strings should return an empty dict.
190 | self.assertEqual(gn_helpers.FromGNArgs(''), {})
191 | self.assertEqual(gn_helpers.FromGNArgs(' \n '), {})
192 |
193 | # Comments should work everywhere (and be ignored).
194 | gn_args_lines = [
195 | '# Top-level comment.',
196 | '',
197 | '# Variable comment.',
198 | 'foo = true',
199 | 'bar = [',
200 | ' # Value comment in list.',
201 | ' 1,',
202 | ' 2,',
203 | ']',
204 | '',
205 | 'baz # Comment anywhere, really',
206 | ' = # also here',
207 | ' 4',
208 | ]
209 | self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)), {
210 | 'foo': True,
211 | 'bar': [1, 2],
212 | 'baz': 4
213 | })
214 |
215 | # Scope should be parsed, even empty ones.
216 | gn_args_lines = [
217 | 'foo = {',
218 | ' a = 1',
219 | ' b = [',
220 | ' { },',
221 | ' {',
222 | ' c = 1',
223 | ' },',
224 | ' ]',
225 | '}',
226 | ]
227 | self.assertEqual(gn_helpers.FromGNArgs('\n'.join(gn_args_lines)),
228 | {'foo': {
229 | 'a': 1,
230 | 'b': [
231 | {},
232 | {
233 | 'c': 1,
234 | },
235 | ]
236 | }})
237 |
238 | # Non-identifiers should raise an exception.
239 | with self.assertRaises(gn_helpers.GNError):
240 | gn_helpers.FromGNArgs('123 = true')
241 |
242 | # References to other variables should raise an exception.
243 | with self.assertRaises(gn_helpers.GNError):
244 | gn_helpers.FromGNArgs('foo = bar')
245 |
246 | # References to functions should raise an exception.
247 | with self.assertRaises(gn_helpers.GNError):
248 | gn_helpers.FromGNArgs('foo = exec_script("//build/baz.py")')
249 |
250 | # Underscores in identifiers should work.
251 | self.assertEqual(gn_helpers.FromGNArgs('_foo = true'),
252 | {'_foo': True})
253 | self.assertEqual(gn_helpers.FromGNArgs('foo_bar = true'),
254 | {'foo_bar': True})
255 | self.assertEqual(gn_helpers.FromGNArgs('foo_=true'),
256 | {'foo_': True})
257 |
258 | def test_ReplaceImports(self):
259 | # Should be a no-op on args inputs without any imports.
260 | parser = gn_helpers.GNValueParser(
261 | textwrap.dedent("""
262 | some_arg1 = "val1"
263 | some_arg2 = "val2"
264 | """))
265 | parser.ReplaceImports()
266 | self.assertEqual(
267 | parser.input,
268 | textwrap.dedent("""
269 | some_arg1 = "val1"
270 | some_arg2 = "val2"
271 | """))
272 |
273 | # A single "import(...)" line should be replaced with the contents of the
274 | # file being imported.
275 | parser = gn_helpers.GNValueParser(
276 | textwrap.dedent("""
277 | some_arg1 = "val1"
278 | import("//some/args/file.gni")
279 | some_arg2 = "val2"
280 | """))
281 | fake_import = 'some_imported_arg = "imported_val"'
282 | if sys.version_info.major < 3:
283 | from mock import patch, mock_open
284 | builtin_var = '__builtin__'
285 | else:
286 | from unittest.mock import patch, mock_open
287 | builtin_var = 'builtins'
288 | open_fun = '{}.open'.format(builtin_var)
289 | with patch(open_fun, mock_open(read_data=fake_import)):
290 | parser.ReplaceImports()
291 | self.assertEqual(
292 | parser.input,
293 | textwrap.dedent("""
294 | some_arg1 = "val1"
295 | some_imported_arg = "imported_val"
296 | some_arg2 = "val2"
297 | """))
298 |
299 | # No trailing parenthesis should raise an exception.
300 | with self.assertRaises(gn_helpers.GNError):
301 | parser = gn_helpers.GNValueParser(
302 | textwrap.dedent('import("//some/args/file.gni"'))
303 | parser.ReplaceImports()
304 |
305 | # No double quotes should raise an exception.
306 | with self.assertRaises(gn_helpers.GNError):
307 | parser = gn_helpers.GNValueParser(
308 | textwrap.dedent('import(//some/args/file.gni)'))
309 | parser.ReplaceImports()
310 |
311 | # A path that's not source absolute should raise an exception.
312 | with self.assertRaises(gn_helpers.GNError):
313 | parser = gn_helpers.GNValueParser(
314 | textwrap.dedent('import("some/relative/args/file.gni")'))
315 | parser.ReplaceImports()
316 |
317 |
318 | if __name__ == '__main__':
319 | unittest.main()
320 |
--------------------------------------------------------------------------------