blob: 369963faa3a8b52519f624cc9ae9ada656cb00c2 [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/assembly/bootfs_files_for_assembly.gni")
import("//build/components.gni")
import("//build/config/zircon/standard.gni")
import("//build/cpp/verify_public_symbols.gni")
import("//build/test.gni")
import("//build/toolchain/ifs_shared_library.gni")
import("//build/zircon/migrated_targets.gni")
import("libc.gni")
import("libc_toolchain.gni")
assert(libc == get_path_info(get_path_info(".", "abspath"), "dir"),
get_path_info(get_path_info(".", "abspath"), "dir"))
# Each subdirectory listed provides some pieces of libc in a uniform way. The
# main target is a source_set() for libc proper and the "unittests" target is a
# libc_test() suitable for inclusion in libc-unittests and Zircon's core-tests.
libc_components = [
"ctype",
"fenv",
"inttypes",
"math",
"pthread",
"scudo",
"stdio",
"stdlib",
"errno",
]
libc_testonly_components = []
if (use_llvm_libc_string_functions) {
libc_components += [ "string" ]
} else {
libc_testonly_components += [ "string" ]
}
group("components") {
visibility = [ ":*" ]
deps = libc_components
}
# This isn't a test per se, but using libc_test will apply the test configs
# we want.
libc_test("test_utils") {
dir = "$llvm_libc/test/UnitTest"
sources = [ "TestLogger.cpp" ]
}
group("unittests") {
testonly = true
deps = [
":test_utils",
"errno:errno.testonly",
]
foreach(subdir,
libc_components + [
"sanitizers",
"zircon",
] + libc_testonly_components) {
deps += [ "$subdir:unittests" ]
}
}
# libc.gni uses these configs.
config("internal.config") {
visibility = [ "./*" ]
configs = [
"//zircon/third_party/ulib/musl:headers",
":llvm-libc.config",
]
}
config("llvm-libc.config") {
visibility = [ "./*" ]
defines = [
"LIBC_COPT_USE_C_ASSERT=1",
"LIBC_NAMESPACE=__llvm_libc",
]
include_dirs = [
libc,
llvm_libc,
]
if (is_gcc) {
# GCC complains about using __m128i type in template speciailization
# because the typedef includes attributes.
cflags = [ "-Wno-ignored-attributes" ]
}
}
config("testonly.config") {
visibility = [ "./*" ]
defines = [ "LIBC_COPT_TEST_USE_FUCHSIA=1" ]
}
config("llvm-libc-export.config") {
visibility = [ "./*" ]
defines = [
"LIBC_COPT_PUBLIC_PACKAGING=1",
"LIBC_INLINE=inline",
]
if (toolchain_environment == "user.libc") {
configs = [ ":llvm-libc-function-attr.config" ]
}
}
config("llvm-libc-function-attr.config") {
visibility = [ "./*" ]
defines = [ "LLVM_LIBC_FUNCTION_ATTR=[[gnu::visibility(\"default\")]]" ]
}
if (current_toolchain == default_toolchain) {
import("//build/toolchain/zircon/zircon_toolchain_suite.gni")
# This introduces a new toolchain suite to mimic the Zircon "user"
# toolchain. Howver, it will only be used to build the C library, so
# is named "user.libc" instead.
foreach(cpu, standard_fuchsia_cpus) {
zircon_toolchain_suite("user.libc_$cpu") {
cpu = cpu
os = "fuchsia"
environment = "user.libc"
with_shared = false
is_pic_default = true
strip = "--strip-sections"
configs = [ "//zircon/system/ulib/c:libc_config" ]
# NOTE: kernel artifacts currently do not build under fuzzer
# variants. This was also true with the Zircon build, but
# the Fuchsia build never invoked it with corresponding
# variant selectors. Using an exclude_variant_tag is
# enough to fix the issue.
exclude_variant_tags = [ "fuzzer" ]
# The Asan-based variants are needed to generate binaries for the SDK.
enable_variants = [ "asan" ]
# TODO(https://fxbug.dev/327442322): Support hwasan for x64 and riscv64.
if (target_cpu == "arm64") {
enable_variants += [ "hwasan" ]
}
}
}
} else if (toolchain_variant.base ==
"//zircon/system/ulib/c:user.libc_$target_cpu") {
config("libc_config") {
configs = [
"//build/config/zircon:user",
"//build/config:shared_library_config",
"//build/config:symbol_no_undefined",
]
# TODO(https://fxbug.dev/42055641): Ensure all of libc uses libcalls into the hwasan
# runtime for storing frame record info.
if (!is_gcc && toolchain_variant.tags + [ "hwasan" ] - [ "hwasan" ] !=
toolchain_variant.tags) {
cflags = [
"-mllvm",
"-hwasan-record-stack-history=libcall",
# This replaces all hwasan load/store checks with an outlined libcall.
# This is done so we can stub out checks on globals which would be tagged
# but before we can actually register their tags into shadow. Note that
# we could alternatively add NO_ASAN on each function that accesses a tagged
# global, but I've found too many instances where globals can be accessed
# in the initial execution path and this is cleaner than adding NO_ASAN
# on each of them.
"-mllvm",
"-hwasan-instrument-with-calls=1",
]
}
}
group("libc_config_deps") {
}
}
# When in a toolchain variant of the Fuchsia base toolchain, find the
# corresponding toolchain variant of user.libc_$target_cpu to build
# the C library with it.
libc_toolchain = sysroot_libc_base_toolchain
if (toolchain_variant.suffix != "") {
libc_toolchain += string_replace(toolchain_variant.suffix, "-fuzzer", "")
} else {
libc_toolchain = system_libc_toolchain
}
# When built with the default/user Fuchsia toolchain, zx_library()
# will not create a :headers sub-target for zx_library("c") below,
# so add one manually as a special case.
if (zircon_toolchain == false) {
group("headers") {
public_configs = [
":headers.config",
"//zircon/third_party/ulib/musl:headers",
]
}
config("headers.config") {
include_dirs = [ "include" ]
}
} else {
config("headers.config") {
include_dirs = [ "include" ]
}
group("headers") {
public_configs = [
"//zircon/third_party/ulib/musl:headers",
# Order of configs matters. This comment prevents re-ordering from 'gn format'.
":headers.config",
]
}
# This builds the actual shared library. It's only used indirectly via the
# "libc" target, see below.
shared_library("libc.so") {
output_name = "c"
visibility = [ ":*" ]
# As a special case, the C library must not be compiled with the default
# configs for shared_library() targets, but those or regular source_set()
# or static_library() targets. In practice, for the base toolchain, this
# means it will be compiled without -fno-rtti, but things get more complicated
# for variant toolchains.
configs -= default_shared_library_configs
configs += default_common_binary_configs
# This directory contains just a libc++.a file that is a stub input linker
# script to prevent the real libc++.a from being found by the linker.
# Instead, it will find the empty file and any references to symbols
# defined in the real libc++.a (which includes libc++abi) will cause the
# link to fail.
lib_dirs = [ "libc++-stub" ]
# At link time and in DT_SONAME, musl is known as libc.so. But the
# (only) place it needs to be installed at runtime is where the
# PT_INTERP strings embedded in executables point, which is ld.so.1.
install_name = "ld.so.1"
metadata = {
runtime_deps_manifest_lines =
[ "lib/${toolchain_variant.libprefix}ld.so.1=" +
rebase_path("$root_out_dir/libc.so", root_build_dir) ]
distribution_entries = [
{
destination = "lib/${toolchain_variant.libprefix}${install_name}"
source = rebase_path("$root_out_dir/libc.so", root_build_dir)
label = get_label_info(target_name, "label_with_toolchain")
elf_runtime_dir = "lib/${toolchain_variant.libprefix}"
},
]
}
public_deps = [ ":headers" ]
# The code comes from musl, where a source_set is defined.
sources = []
deps = [
":components",
":exit",
"sanitizers",
"setjmp",
"stubs",
"zircon",
"//src/zircon/lib/zircon",
"//zircon/system/ulib/zx-panic-libc:as_source",
"//zircon/third_party/ulib/musl",
]
# Don't link against the shared libc++.
configs += [ "//build/config/zircon:static-libc++" ]
if (!is_gcc && current_cpu == "riscv64" &&
toolchain_variant.tags + [ "instrumented" ] - [ "instrumented" ] !=
toolchain_variant.tags) {
# TODO(https://fxbug.dev/42072830): There is no R_RISCV_GLOB_DAT and instead
# R_RISCV_64 is used for all GOT relocs; this means that they all must be
# presumed to have potentially nonzero addends that matter. The ld.so
# bootstrap hack of saving the in-place DT_REL addends on the stack
# depends on the total number of addend-using relocs in ld.so being
# fairly small. Luckily, it normally is even with all its plain GOT
# slots requiring addends (though in practice they're probably all zero
# anyway). However, with instrumentation that makes runtime outcalls
# that number can increase quite a lot. So when building with such
# instrumentation, stick to DT_RELA format where the addend-saving hack
# is not required at all. The profile instrumentation doesn't use
# outcalls but happens to increase the number of relocs too.
ldflags = [ "-Wl,-z,rela" ]
}
}
}
source_set("exit") {
sources = [ "_Exit.cc" ]
deps = [ "//zircon/third_party/ulib/musl:musl_internal" ]
}
if (zircon_toolchain == false) {
# Don't build the C runtime startup object in the Fuchsia user
# toolchain, because this adds many unwanted dependencies to fdio,
# trace-engine and whatnot that are completely un-needed and also
# interfere with sysroot generation. Use the C library toolchain instead.
group("crt1") {
public_deps = [ ":crt1($libc_toolchain)" ]
}
} else {
source_set("crt1") {
sources = [ "Scrt1.cc" ]
# This runs before all runtime setup.
configs += [ "//build/config/sanitizers:no_sanitizers" ]
# Minimize the code. Even if there were lazy PLT resolution, it's never
# worthwhile to have PLT entries for main or __libc_start_main, since
# they are always used eagerly anyway.
cflags = [ "-fno-plt" ]
# The C runtime is needed for Go builds and the SDK, so always download this locally.
if (cxx_rbe_enable && !cxx_rbe_download_obj_files) {
configs += [ "//build/config:download_outputs" ]
}
}
}
# This gets the actual shared_library() target defined above.
libc_impl_label = ":libc.so($libc_toolchain)"
# This is used by the sysroot creation (see libc_toolchain.gni and
# sysroot_entries.gni). It reaches the actual implementation binary, to get it
# built and packaged, and also ensures the implementation has been checked
# against the checked-in libc.ifs file.
group("libc") {
visibility = [
":*",
"//zircon/public/sysroot/*",
]
# This has to be public_deps so that the shared_library() target's output
# files can be input files of the setup and packaging targets that depend on
# this "libc" wrapper target.
public_deps = [ libc_impl_label ]
deps = [ ":verify_abi" ]
}
bootfs_files_for_assembly("bootfs") {
deps = [ libc_impl_label ]
}
verify_public_symbols("verify_abi") {
visibility = [ ":*" ]
deps = [ libc_impl_label ]
current = get_label_info(libc_impl_label, "root_out_dir") + "/libc.ifs"
reference = "libc.ifs"
library_name = "libc"
# libc conditionally exports weak sanitizer symbols to satisfy references
# to this symbols from libc. They are not meant to be exported, the actual
# symbols provided by the sanitizer libraries will be loaded before
# any user code needs them. See sanitizer/{asan,hwasan,ubsan}-stubs.cc for
# detailed explanations.
ifs_args = [
"--exclude=__asan*",
"--exclude=__hwasan*",
"--exclude=__ubsan*",
]
}
# This is the linking stub that binaries are actually linked against.
# //zircon/public/sysroot:cpp_binary_deps is in the implicit deps added to
# every target, and it uses this.
ifs_shared_library("c") {
abi = "libc.ifs"
}
group("tests") {
testonly = true
deps = [ "test" ]
}
group("boot_tests") {
testonly = true
deps = [ "test:boot_tests" ]
}