| # Copyright 2020 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. | 
 |  | 
 | # This file exists to find the GN toolchain() instance used to build | 
 | # the version of the C library used for regular Fuchsia packages (which is | 
 | # potentially instrumented), as well as the version used by the Fuchsia | 
 | # system package (which may be different, as it must not be instrumented, | 
 | # but could still be built with a variant like "gcc" or "thinlto"). | 
 | # | 
 | # For more details, see the extensive TECHNICAL NOTE in the comments at | 
 | # the end of this file. | 
 |  | 
 | import("//build/toolchain/zircon/clang.gni") | 
 |  | 
 | # The C library's own GN target label, without a toolchain | 
 | sysroot_libc_label = "//zircon/system/ulib/c" | 
 |  | 
 | # The base toolchain used to build the C library. This is the toolchain that is used | 
 | # when no variant is selected by the user through `select_variant` in args.gn. | 
 | sysroot_libc_base_toolchain = "//zircon/system/ulib/c:user.libc_$target_cpu" | 
 |  | 
 | # The variant selector fields corresponding to the C library. | 
 | # Keep it in sync with the definitions of user.libc_${target_cpu} | 
 | # in //zircon/system/ulib/c/BUILD.gn! | 
 | # | 
 | _select_host = false | 
 | _select_testonly = false | 
 | _select_target_type = [ "shared_library" ] | 
 | _select_output_name = [ "libc.so" ] | 
 | _select_label = [ "//zircon/system/ulib/c" ] | 
 | _select_name = [ "libc" ] | 
 | _select_dir = [ "//zircon/system/ulib/c" ] | 
 | _select_exclude_toolchain_tags = [ "fuzzer" ] | 
 |  | 
 | # ====================================================================== | 
 | # START OF CODE TO KEEP IN SYNC WITH BUILDCONFIG.gn | 
 | # | 
 | # IMPORTANT: Always keep the code below in sync with the computations | 
 | # performed by variant_target() within //build/config/BUILDCONFIG.gn. | 
 | # | 
 | _instrumented_target_variant = "" | 
 | _uninstrumented_target_variant = "" | 
 |  | 
 | if (select_variant_canonical != []) { | 
 |   _selected = false | 
 |  | 
 |   foreach(selector, select_variant_canonical) { | 
 |     if (_instrumented_target_variant == "" || | 
 |         _uninstrumented_target_variant == "") { | 
 |       _selector = { | 
 |       } | 
 |       _selector = { | 
 |         target_type = [] | 
 |         output_name = [] | 
 |         label = [] | 
 |         name = [] | 
 |         dir = [] | 
 |         forward_variables_from(selector, "*") | 
 |       } | 
 |  | 
 |       _selected = true | 
 |       if (_selected && defined(_selector.host)) { | 
 |         _selected = _selector.host == _select_host | 
 |       } | 
 |  | 
 |       if (_selected && defined(_selector.testonly)) { | 
 |         _selected = _selector.testonly == _select_testonly | 
 |       } | 
 |  | 
 |       if (_selected && _selector.target_type != []) { | 
 |         _selected = _selector.target_type + _select_target_type - | 
 |                     _select_target_type != _selector.target_type | 
 |       } | 
 |  | 
 |       if (_selected && _selector.output_name != []) { | 
 |         _selected = _selector.output_name + _select_output_name - | 
 |                     _select_output_name != _selector.output_name | 
 |       } | 
 |  | 
 |       if (_selected && _selector.label != []) { | 
 |         _selected = | 
 |             _selector.label + _select_label - _select_label != _selector.label | 
 |       } | 
 |  | 
 |       if (_selected && _selector.name != []) { | 
 |         _selected = | 
 |             _selector.name + _select_name - _select_name != _selector.name | 
 |       } | 
 |  | 
 |       if (_selected && _selector.dir != []) { | 
 |         _selected = _selector.dir + _select_dir - _select_dir != _selector.dir | 
 |       } | 
 |  | 
 |       if (_selected && _select_exclude_toolchain_tags != []) { | 
 |         _selected = _select_exclude_toolchain_tags + _selector.variant_tags - | 
 |                     _selector.variant_tags == _select_exclude_toolchain_tags | 
 |       } | 
 |  | 
 |       if (_selected && _selector.variant != false) { | 
 |         if (_selector.variant_tags + [ "instrumented" ] - [ "instrumented" ] != | 
 |             _selector.variant_tags) { | 
 |           if (_instrumented_target_variant == "") { | 
 |             _instrumented_target_variant = "-${_selector.variant}" | 
 |           } | 
 |         } else if (_uninstrumented_target_variant == "") { | 
 |           _uninstrumented_target_variant = "-${_selector.variant}" | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | # END OF CODE TO KEEP IN SYNC WITH BUILDCONFIG.gn! | 
 | # ================================================================== | 
 |  | 
 | # See technical note below to understand why these computations are necessary. | 
 | if (_instrumented_target_variant != "") { | 
 |   _user_target_variant = _instrumented_target_variant | 
 | } else { | 
 |   _user_target_variant = _uninstrumented_target_variant | 
 | } | 
 |  | 
 | _system_target_variant = _uninstrumented_target_variant | 
 |  | 
 | # This is the toolchain used to build the C library that appears in the system package, | 
 | # i.e. that is installed under /lib/ld.so.1. It must be a non-instrumented version of | 
 | # the library, though a variant like "gcc" might be applied to it. | 
 | system_libc_toolchain = sysroot_libc_base_toolchain + _system_target_variant | 
 |  | 
 | if (is_fuchsia) { | 
 |   # 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. | 
 |   sysroot_libc_toolchain = sysroot_libc_base_toolchain | 
 |   if (toolchain_variant.suffix != "") { | 
 |     sysroot_libc_toolchain = | 
 |         sysroot_libc_base_toolchain + | 
 |         string_replace(toolchain_variant.suffix, "-fuzzer", "") | 
 |   } else { | 
 |     sysroot_libc_toolchain = system_libc_toolchain | 
 |   } | 
 | } else { | 
 |   # This is the toolchain used to build the C library for regular Fuchsia packages. | 
 |   # If an instrumented toolchain is used, it will be installed as lib/<variant>/ld.so.1 | 
 |   # as expected by other user-level binaries. | 
 |   sysroot_libc_toolchain = sysroot_libc_base_toolchain + _user_target_variant | 
 | } | 
 |  | 
 | # The GN target that builds the C library for the current variant selection. | 
 | sysroot_libc_target = "$sysroot_libc_label:libc($sysroot_libc_toolchain)" | 
 | sysroot_libc_stub_target = "$sysroot_libc_label($sysroot_libc_toolchain)" | 
 |  | 
 | # The paths to the binaries generated by the C library target. Note that these | 
 | # are called libc.so, but are installed in packages or the system as ld.so.1. | 
 | sysroot_libc_stripped = | 
 |     get_label_info(sysroot_libc_target, "root_out_dir") + "/libc.so" | 
 | sysroot_libc_unstripped = sysroot_libc_stripped + ".debug" | 
 | sysroot_libc_stub = get_label_info("$sysroot_libc_label($default_toolchain)", | 
 |                                    "target_gen_dir") + "/c.$clang_cpu/libc.so" | 
 |  | 
 | # The GN target that builds the system C library. This is required for certain | 
 | # binaries that are placed in the system package, and expect to find the library | 
 | # under lib/ld.so.1, instead of lib/<variant>/ld.so.1 | 
 | system_libc_target = "$sysroot_libc_label:libc($system_libc_toolchain)" | 
 | system_libc_stripped = | 
 |     get_label_info(system_libc_target, "root_out_dir") + "/libc.so" | 
 | system_libc_unstripped = system_libc_stripped + ".debug" | 
 |  | 
 | # The C runtime startup object, which must be linked to all Fuchsia executable | 
 | # binaries. | 
 | sysroot_crt1_toolchain = sysroot_libc_toolchain | 
 | sysroot_crt1_target = "//zircon/system/ulib/c:crt1($sysroot_crt1_toolchain)" | 
 |  | 
 | sysroot_crt1_obj = | 
 |     get_label_info(sysroot_crt1_target, "target_out_dir") + "/crt1.Scrt1.cc.o" | 
 | # TECHNICAL NOTE | 
 | # | 
 | # This file exists because the C library, while technically not part of the | 
 | # system in Fuchsia, still requires very special care during the build. | 
 | # | 
 | # Its main purpose is to find the GN toolchain() instance that is used to | 
 | # build the uninstrumented version of 'libc.so', based on the current set | 
 | # of variant selectors (i.e. 'select_variant' as defined in | 
 | # 'out/default/args.gn') | 
 | # | 
 | # Some critical considerations to be aware of to understand what's below: | 
 | # | 
 | # - The C library is built as 'libc.so' and 'libc.so.debug', for the stripped | 
 | #   and unstripped versions, respectively. | 
 | # | 
 | #   The stripped version is installed into Fuchsia packages and is used | 
 | #   at runtime. The unstripped version is used at link time and for | 
 | #   debugging + symbolization. | 
 | # | 
 | # - The C library can be built with GCC, instead of Clang. This is usually | 
 | #   done by enabling the "gcc" variant, which is ignored by non-Zircon specific | 
 | #   targets (in other words, Fuchsia user binaries are never built with GCC | 
 | #   even if this variant is enabled). | 
 | # | 
 | # - The stripped C library (libc.so) will be installed as 'lib/ld.so.1' | 
 | #   by default within Fuchsia packages. This is because it implements both | 
 | #   the C runtime and the dynamic loader at the same time. Fuchsia user | 
 | #   executables contain a direct reference to this location inside their | 
 | #   dynamic section. | 
 | # | 
 | #   However, a Fuchsia executable built with an _instrumented_ variant, | 
 | #   will look at runtime for 'lib/<variant>/ld.so.1' instead, which | 
 | #   should contain the version of 'libc.so' compiled for the same variant. | 
 | # | 
 | #   E.g., if the "asan" variant is enabled, then an executable installed | 
 | #   as 'bin/program' will use 'lib/asan/ld.so.1' to find the dynamic loader, | 
 | #   and this file should be a copy of 'out/default/user.libc_x64-asan/libc.so'. | 
 | # | 
 | #   Hence, which version of the C library is associated with a given | 
 | #   executable binary depends on the variant used to build it. | 
 | # | 
 | #   As a reminder, our build system provides the ability to enable different | 
 | #   variants for different targets, e.g.: | 
 | # | 
 | #     select_variant = [ | 
 | #       "ubsan/cat", | 
 | #       "profile/echo", | 
 | #       "asan" | 
 | #     ] | 
 | # | 
 | #   Would build the 'cat' executable with the 'ubsan' variant, the | 
 | #   'echo' one with the 'profile' variant, and all other Fuchsia executables | 
 | #   with the 'asan' one. | 
 | # | 
 | # - Even if no variant is enabled in a given build, the "asan" and "asan-ubsan" | 
 | #   variants of the C library need to be built and exported to the Fuchsia SDK. | 
 | #   (see //zircon/system/ulib/c/sysroot_entries.gni for details). | 
 | # | 
 | # - The "system package" is a special Fuchsia package that contains system | 
 | #   libraries and binaries (i.e. those required to boot the system). It requires | 
 | #   an un-instrumented C library in 'lib/ld.so.1', since several prebuilt | 
 | #   driver binaries depend on it. | 
 | # | 
 | #   And this, even if a variant is enabled to build all Fuchsia binaries. | 
 | #   Note that non-instrumented variants still need to apply to this binary | 
 | #   (e.g. "gcc" or "thinlto"). | 
 | # | 
 | # - Finally, when linking executables or ELF shared objects, the C++ compiler | 
 | #   will by default inject implicit dependencies to various libraries and | 
 | #   object files, i.e.: | 
 | # | 
 | #    - Adding an implicit '-lc' and '-lm' link argument before invoking | 
 | #      the final linker program. | 
 | # | 
 | #    - Adding implicit dependencies to compiler-builtins support libraries | 
 | #      (e.g. '-lgcc'), the C++ runtime library (e.g. '-lc++') and other | 
 | #      instrumentation-related runtime libraries (e.g. '-lclang_rt.asan') | 
 | #      when needed. | 
 | # | 
 | #    - For ELF executables, it will also search for a file named 'Scrt1.o' | 
 | #      which contains the low-level C runtime startup code (i.e. the | 
 | #      one that implements the '_start' entry point, called by the | 
 | #      system once the executable and its dependent libraries are | 
 | #      loaded, its role is to initialize the C runtime, then jump | 
 | #      off to the main() function). | 
 | # | 
 | #   All of these can be controlled by an array of compiler/linker flags, | 
 | #   the most important one being the --sysroot=DIR option used to specify | 
 | #   the location of these system headers and libraries at build time. | 
 | # | 
 | # - Rust and Go binaries do not participate in variant selection. As such | 
 | #   they should always be linked against a non-instrumented version of | 
 | #   the C library, even if an instrumented variant is used for other | 
 | #   C++ Fuchsia binaries. | 
 | # | 
 | # - Apparently, it is ok to link an instrumented executable or loadable | 
 | #   module against a non-instrumented C library at build time, as long | 
 | #   as the proper instrumented binary is installed into the corresponding | 
 | #   Fuchsia package. | 
 | #   It may be possible to use the right instrumented C library at link time | 
 | #   instead. |