blob: f277419cd02205bc97fed52f7f2479df429eca30 [file] [log] [blame]
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/board.gni")
import("//build/config/build_id.gni")
import("//build/config/clang/clang.gni")
import("//build/config/clang/crash_diagnostics.gni")
import("//build/config/compiler.gni")
import("//build/config/linker.gni")
import("//build/config/zircon/levels.gni")
import("//build/toolchain/variant.gni")
# NOTE: This file provides the GN configs used by Zircon toolchains
# exclusively. See //build/toolchain/zircon/zircon_toolchain.gni.
#
# Major differences in the rewrite:
#
# - Uses |zircon_toolchain| global variable, instead of |toolchain|.
#
# - All code paths related to |is_host| has been removed (the Zircon toolchain
# are never used to build host binaries).
# These flags are enabled by default in Fuchsia's Clang toolchain, but we set
# them explicitly to support other Clang toolchains and Clang-based tools.
config("clang_defaults") {
if (clang_embed_bitcode) {
cflags += [
"-Xclang",
"-fembed-bitcode=all",
]
}
if (current_cpu == "x64") {
asmflags = [ "-Wa,--mrelax-relocations=yes" ]
}
if (current_os == "linux") {
cflags_cc = [ "-stdlib=libc++" ]
ldflags = [
"-stdlib=libc++",
"-unwindlib=libunwind",
"-rtlib=compiler-rt",
]
}
}
config("compiler") {
# Per CPU targeting policy we always target the baseline when building the
# kernel, rather than using board_configs. This is done to reduce binary
# diversity. See: TODO RFC LINK HERE
configs = [ "//build/config:cpu_baseline" ]
compiler_flags = []
cflags_cc = []
defines = []
ldflags = []
# NOTE: This config should only be used with Zircon-specific toolchains
# but this BUILD.gn file is also included from non-Zircon ones. To
# avoid un-necessary GN errors, define a fake local zircon_toolchain
# scope to ensure this config() definitions executes properly even if
# it is never used.
if (zircon_toolchain == false) {
zircon_toolchain = {
target_tuple = ""
version_string = ""
include_dirs_cc = []
lib_dirs = []
}
}
# For GCC, the compiler command implies the target.
# For Clang, there's a single compiler command that takes `--target`.
if (!is_gcc) {
compiler_flags += [ "--target=${zircon_toolchain.target_tuple}" ]
}
if (linker != "") {
ldflags += [ "-fuse-ld=$linker" ]
}
if (defined(zircon_toolchain.version_string) &&
zircon_toolchain.version_string != "") {
# Nothing uses this define, but its presence on compilation command
# lines ensures that Ninja will rebuild things when a new compiler
# version arrives.
defines += [ "TOOLCHAIN_VERSION=${zircon_toolchain.version_string}" ]
}
# This is the default already on Fuchsia and maybe others, but never hurts.
cflags = [ "-fno-common" ]
configs += [
"//build/config:color_diagnostics",
"//build/config:crash_diagnostics",
# TODO: "$current_os:compiler",
]
if (!is_gcc) {
configs += [ ":clang_defaults" ]
}
if (is_fuchsia) {
# ld.bfd doesn't support -z relro for the targets we use it for.
if (!is_gcc || linker == "gold") {
ldflags += [ "-Wl,-z,relro" ]
}
if (is_gcc) {
# This is predefined by Clang --target=*-fuchsia.
# But the GCC toolchain is the generic --target=*-elf one.
defines += [ "__Fuchsia__" ]
# These are done by default in the Clang toolchain.
cflags += [ "-fasynchronous-unwind-tables" ]
ldflags += [
"-Wl,--build-id",
"-Wl,--hash-style=gnu",
"-Wl,-z,now",
"-Wl,-z,combreloc",
"-Wl,-z,text",
]
if (!is_kernel) {
ldflags += [ "-Wl,--eh-frame-hdr" ]
}
if (linker == "" || linker == "bfd") {
# This is the default in both LLD and Gold, but not in BFD.
# However, Gold doesn't even have the switch.
ldflags += [ "-Wl,-z,separate-code" ]
}
# In the Clang toolchain assembly files with no explicit marker don't
# cause the presumption of executable stack as they do in GCC.
ldflags += [ "-Wl,-z,noexecstack" ]
if (current_cpu == "arm64") {
# x18 is reserved in the Fuchsia ABI so it can be used
# for things like -fsanitize=shadow-call-stack.
cflags += [ "-ffixed-x18" ]
}
} else {
# gcc defaults to enabling sized deallocation >= c++14; clang does not.
# Enable sized-deallocation for the kernel, so the heap implementation can
# optimize for or check generated sizes.
cflags += [ "-fsized-deallocation" ]
}
} else if (current_os == "win") {
# This enables build ID-like PDB UUIDs without timestamp.
ldflags += [ "-Wl,/Brepro" ]
}
# The toolchain-supplied headers come after include_dirs from targets and
# configs but before libc.
foreach(dir, zircon_toolchain.include_dirs_cc) {
cflags_cc += [
"-isystem",
rebase_path(dir, root_build_dir),
]
}
lib_dirs = zircon_toolchain.lib_dirs
asmflags = compiler_flags
cflags += compiler_flags
ldflags += compiler_flags
if (is_fuchsia && build_id_format != "") {
ldflags += [ "-Wl,--build-id=$build_id_format" ]
}
}
config("nolibc") {
ldflags = [ "-nostartfiles" ]
# Don't use -nostdlib, because the builtins (or libgcc) are what we want
# and are otherwise annoying to find and specify. It's just the -lc that
# we really want to defeat, and that's handled by giving a -L that will
# find exactly nothing but a dummy libc.so. Clang has -nolibc to kill
# the -lc, but for C++ it still uses -lm under -nolibc. So this is still
# needed to make -lm into a dummy, though for -lc only GCC needs it.
lib_dirs = [ "libc-dummy" ]
if (is_gcc) {
# Include this in every link.
# Note GN requires "./" so it doesn't think this should mean a -l switch.
libs = [ "./dso_handle.ld" ]
} else {
# TODO(mcgrathr): GCC 9 has -nolibc, so use it when we get that toolchain.
ldflags += [ "-nolibc" ]
}
}
config("freestanding") {
cflags = [ "-ffreestanding" ]
# In Clang -fasynchronous-unwind-tables is the default for *-fuchsia
# targets. But -ffreestanding defeats that (in target-independent logic
# in the Clang driver). So add it back explicitly. For GCC, it's
# already added explicitly in :compiler regardless so don't double it.
if (!is_gcc) {
cflags += [ "-fasynchronous-unwind-tables" ]
}
ldflags = cflags
}
config("data_sections") {
cflags = [ "-fdata-sections" ]
ldflags = cflags
}
# The 'default_assert_level' will point to one of the assert_level_<n> values
# below. This allows targets or toolchains to opt out from the default and
# select a specific value.
foreach(level,
[
0,
1,
2,
]) {
variant("assert_level_$level") {
defines = [ "ZX_ASSERT_LEVEL=$level" ]
if (level == 0) {
defines += [ "NDEBUG" ]
}
}
}
variant("default_assert_level") {
assert(
zx_assert_level >= 0 && zx_assert_level <= 2,
"Invalid zx_assert_level value '$zx_assert_level', valid values are 0, 1 or 2")
configs = [ ":assert_level_$zx_assert_level" ]
}
# This is separate from default_optimize so it can be removed.
config("default_icf") {
if (optimize != "none" && optimize != "debug") {
# Our code should never rely on C's unique function pointer semantics,
# which is broken by --icf=all for sometimes substantial space savings.
configs = [ "//build/config:icf" ]
}
}
config("default_template_backtrace_limit") {
cflags_cc = [ "-ftemplate-backtrace-limit=0" ]
}
config("no_threadsafe_statics") {
cflags_cc = [ "-fno-threadsafe-statics" ]
cflags_objcc = cflags_cc
}
config("default_include_dirs") {
include_dirs = [ "//zircon/system/public" ]
}
config("no_fuzzer") {
if (!is_gcc) {
cflags = [ "-fno-sanitize=fuzzer" ]
}
}
# TODO(fxbug.dev/27266) Remove this once the warning with fit::variant is addressed.
config("no_maybe_uninitialized") {
if (is_gcc) {
cflags = [ "-Wno-maybe-uninitialized" ]
}
}
config("machine") {
if (is_fuchsia && is_gcc) {
# TODO(fxbug.dev/32157): Really need to get this nailed down once and for all
# and set by default in the compiler driver (Clang at least).
ldflags = [ "-Wl,-z,max-page-size=4096" ]
}
}
# TODO(fxbug.dev/54322): Use the config under //third_party/ulib/musl once the C
# library has been migrated to the GN build.
config("musl_headers") {
_musl_dir = "//zircon/third_party/ulib/musl"
visibility = [
"${_musl_dir}/*",
"//zircon/system/ulib/c:*",
]
cflags = [
"-idirafter",
rebase_path("${_musl_dir}/include", root_build_dir),
]
asmflags = cflags
}
variant("user") {
defines = [ "_ALL_SOURCE" ]
configs = [
":nolibc",
":musl_headers",
]
if (is_gcc) {
# This is the default in Clang for Fuchsia targets. In shlib toolchains
# this config will come before the one that overrides it with -fPIC.
common_flags = [ "-fPIE" ]
}
}
variant("user-executable") {
# This prevents the default dynamic linker from being embedded. Other deps
# can still set PT_INTERP either via link inputs with a `.interp` section, or
# ldflags that come later with an explicit `-Wl,-dynamic-linker=...`.
ldflags = [ "-Wl,--no-dynamic-linker" ]
if (is_gcc) {
# This is already the default in Clang for Fuchsia targets.
ldflags += [ "-pie" ]
# Gold doesn't handle --no-dynamic-linker and won't produce a PIE without a
# PT_INTERP.
ldflags += [ "-fuse-ld=bfd" ]
}
# crt1 and libc will come via explicit link dependencies if at all.
ldflags += [
"-nostartfiles",
"-nolibc",
]
}
config("integer-paranoia") {
cflags = [
"-fsanitize=integer-divide-by-zero,signed-integer-overflow",
"-fsanitize-undefined-trap-on-error",
]
}
config("static-libc++") {
if (current_os == "mac") {
# The macOS driver doesn't support -static-libstdc++ properly, so pass
# the libraries directly. This has to locate the files explicitly in
# the toolchain, because -lc++ would look for the shared library.
ldflags = [
"-nostdlib++",
# NOTE: the path below was relative to toolchain.tool_dir in the Zircon build
# but the Fuchsia one doesn't support GCC-based host builds at all, so this
# is assuming Clang is always used instead.
"${rebased_clang_prefix}/../lib/libc++.a",
]
} else {
ldflags = [ "-static-libstdc++" ]
# TODO(fxbug.dev/26846): The implicitly linked static libc++.a depends on these.
if (current_os == "linux") {
libs = [
"dl",
"pthread",
]
}
}
}
# This config is used for code that needs to be purely position-independent
# without using dynamic relocation. Since the compiler doesn't generally make
# guarantees about this, it's sometimes necessary to disable specific optimizations
# to ensure the code with this requirement doesn't get compiled in ways that won't
# work. This config can be changed to add switches when those needs arise.
config("pure") {
# TODO(fxbug.dev/125225): This disables the SwitchToLookupTable optimization,
# which is not PIC-friendly under LTO.
if ((current_toolchain == shlib_toolchain ||
toolchain_variant.is_pic_default) &&
toolchain_variant.tags + [ "lto" ] - [ "lto" ] !=
toolchain_variant.tags) {
cflags = [ "-fno-jump-tables" ]
}
}
variant("rodso") {
configs = [ ":pure" ]
if (is_gcc) {
inputs = [ "rodso.ld" ]
ldflags = [ "-Wl,-T," + rebase_path(inputs[0], root_build_dir) ]
}
}
# This has to be variant() rather than config() to be used in the toolchain
# configs list.
variant("tiny") {
cflags = [ "-mcmodel=tiny" ]
asmflags = cflags
ldflags = cflags
}
# Statically linked posititon independent executable.
#
# These have to be variant() rather than config() to be used in the toolchain
# configs list.
variant("static-pie-compile") {
cflags = [ "-fPIE" ]
}
variant("static-pie-link") {
ldflags = [
"-Wl,-pie",
"-Wl,--no-dynamic-linker",
]
}
# Disallow C++ static initializers in functions that require runtime init.
config("forbid-guard-variables") {
if (!is_gcc) {
cflags_cc = [
"-Xclang",
"-fforbid-guard-variables",
]
}
}
# This is used by hermetic_code_blob() in hermetic_code_blob.gni.
config("hermetic-code-blob") {
inputs = [ "hermetic-code-blob.ld" ]
# Use a custom linker script rather than the default PIE layout.
ldflags = [ "-Wl,-T," + rebase_path(inputs[0], root_build_dir) ]
# lld defaults to PIE, while the GNU linkers do not.
if (!is_gcc) {
ldflags += [ "-Wl,--no-pie" ]
}
# Don't add any additional sections or dependencies.
ldflags += [
"-Wl,--build-id=none",
"-Wl,--no-dynamic-linker",
"-Wl,--no-eh-frame-hdr",
]
if (!is_kernel) {
ldflags += [
"-static",
"-nostartfiles",
]
if (is_gcc) {
ldflags += [ "-nostdlib" ]
} else {
# Note this can still link in builtins, which is generally OK for user
# code (even the basic machine ABI), but not for kernel code that has its
# own ABI requirements.
ldflags += [
"-nolibc",
"-nostdlib++",
"-unwindlib=none",
]
}
}
}