| # 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 |
| } |
| |
| # The older code neither from musl nor from llvm-libc does not have |
| # corresponding unit tests. |
| group("legacy-components") { |
| visibility = [ ":*" ] |
| deps = [ |
| "sanitizers", |
| "setjmp", |
| "stubs", |
| "zircon", |
| "//zircon/system/ulib/zx-panic-libc:as_source", |
| ] |
| } |
| |
| # 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. |
| |
| # This is used for all libc-related sources, because some of the local code |
| # still ties into the old musl implementation. When the interactions with musl |
| # internals are fully replaced, only llvm-libc.config will be needed. |
| config("internal.config") { |
| visibility = [ "./*" ] |
| configs = [ |
| "//zircon/third_party/ulib/musl:headers", |
| ":llvm-libc.config", |
| ] |
| } |
| |
| # This is needed for the expectations of the llvm-libc source code, whether |
| # compiled into libc or just into unit test code. |
| config("llvm-libc.config") { |
| visibility = [ "./*" ] |
| defines = [ "LIBC_COPT_USE_C_ASSERT=1" ] |
| include_dirs = [ |
| ".", |
| |
| # TODO(https://fxbug.dev/42105189): This directory provides headers to |
| # preempt and wrap certain llvm-libc headers to work around the |
| # incompatibility of the namespace-unclean Zircon headers. |
| "include-preempt", |
| |
| llvm_libc, |
| ] |
| |
| if (is_gcc) { |
| # GCC complains about using __m128i type in template speciailization |
| # because the typedef includes attributes. |
| cflags = [ "-Wno-ignored-attributes" ] |
| } |
| } |
| |
| # This is needed when compiling libc-related code for use in unit tests. |
| config("testonly.config") { |
| visibility = [ "./*" ] |
| defines = [ |
| "LIBC_COPT_TEST_USE_ZXTEST", |
| |
| # TODO(mcgrathr): This is being replaced by LIBC_COPT_TEST_USE_ZXTEST, |
| # but during the transition both are needed. |
| "LIBC_COPT_TEST_USE_FUCHSIA", |
| |
| # This namespace is different from the one used below for building libc |
| # itself, mostly just for more visual clarity looking at backtraces from |
| # unit test code and such. Since the unit test code only ever gets linked |
| # into a program using libc.so and not statically linked with the non-test |
| # libc code, it's not actually ambiguous what it means in the context of |
| # which binary contained the symbol. But using a separate name is clearer. |
| "LIBC_NAMESPACE=llvm_libc_unittest", |
| ] |
| } |
| |
| # This is needed for compilations of libc-related code to be used in |
| # production, not in unit tests. This applies both to things used outside of |
| # libc proper, such as the separate printf_core integrations; and to libc.so |
| # itself, which uses llvm-libc-extra.config, below. |
| config("llvm-libc-public.config") { |
| configs = [ ":llvm-libc.config" ] |
| |
| defines = [ |
| # This namespace is invisible to anything outside libc.so, though in an |
| # eventual libc.a for static linking it would be visible at static link |
| # time. The separate integrations of parts of libc internals, such as |
| # printf_core, also use this namespace because the libc_source_set()s they |
| # depend on are shared targets that also go into libc proper. In effect, |
| # those separate integrations are using subsets of what an eventual libc.a |
| # could provide to those use cases. |
| # |
| # TODO(mcgrathr): There's no important reason to make it either the same or |
| # different from the upstream default of `__llvm_libc`, but it seems like |
| # `__fuchsia_libc` would be preferable just to make it more clear that this |
| # build is quite different from the llvm-libc source tree's own cmake (or |
| # Bazel) build of the same llvm-libc code. For now, there are a few places |
| # that hard-code `__llvm_libc` elsewhere in the source tree. Perhaps |
| # rewire those to use some shared source of truth with this somehow. |
| "LIBC_NAMESPACE=__llvm_libc", |
| ] |
| } |
| |
| config("llvm-libc-export.config") { |
| visibility = [ "./*" ] |
| |
| configs = [ ":llvm-libc-public.config" ] |
| |
| defines = [ "LIBC_COPT_PUBLIC_PACKAGING=1" ] |
| |
| if (toolchain_environment == "user.libc") { |
| configs += [ ":llvm-libc-function-attr.config" ] |
| |
| # libfuzzer also uses libc internally. By removing the fuzzing |
| # instrumentation we avoid it adding noise to the fuzzing coverage. |
| # TODO(https://fxbug.dev/25073): Once a cleaner solution is found, remove |
| # this. |
| configs += [ "//build/config/zircon:no_fuzzer" ] |
| } |
| } |
| |
| 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", |
| ] |
| } |
| |
| config("libc-shlib.config") { |
| visibility = [ ":*" ] |
| |
| # Don't link against the shared libc++. |
| configs = [ "//build/config/zircon:static-libc++" ] |
| |
| # 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" ] |
| } |
| |
| # 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 |
| |
| configs += [ ":libc-shlib.config" ] |
| |
| # 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" ] |
| |
| deps = [ |
| ":components", |
| ":legacy-components", |
| "//zircon/third_party/ulib/musl:legacy-impl", |
| ] |
| |
| 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" ] |
| } |
| } |
| } |
| |
| 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" ] |
| } |
| |
| group("libc_fshost") { |
| visibility = [ "//bundles/assembly/*" ] |
| |
| # 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 ] |
| } |
| |
| 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" ] |
| } |