|  | # 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. | 
|  |  | 
|  | import("//build/config/clang/clang.gni") | 
|  | import("//build/config/clang/clang_toolchain_info.gni") | 
|  | import("//build/rust/config.gni") | 
|  | import("//build/toolchain/zircon/clang.gni") | 
|  |  | 
|  | # ## runtime.json | 
|  | # | 
|  | # Each toolchain (i.e. Clang or rustc) provides a "runtime.json" file | 
|  | # in its top-level lib/ sub-directory. | 
|  | # | 
|  | # This file is provided by the toolchain to describe the runtime | 
|  | # dependencies implied by linking a binary based on --target and other | 
|  | # compiler switches.  The file contains a JSON array of objects that map to | 
|  | # the following GN schema.  Each entry matches a single compilation mode | 
|  | # and yields all the runtime dependencies implied by that mode. | 
|  | # | 
|  | # Type: list(scope) | 
|  | # | 
|  | # * target | 
|  | #   - Required: --target tuples a la `${current_target_tuple}`. | 
|  | #   - Type: list(string) | 
|  | # | 
|  | # * cflags | 
|  | #   - Optional: List of compilation flags that select this mode, | 
|  | #     e.g. `"-fsanitizer=..."` and the like. | 
|  | #     If not specified, cflags are ignored during selection. | 
|  | #   - Type: list(string) | 
|  | # | 
|  | # * ldflags | 
|  | #   - Optional: Link-time flags that select this mode. | 
|  | #     This is usually either `[ "-static-libstdc++" ]` or `[]`. | 
|  | #     If not specified, ldflags are ignored during selection. | 
|  | #   - Type: list(string) | 
|  | # | 
|  | # * runtime | 
|  | #   - Required: List of runtime files needed by binaries in this mode. | 
|  | #   - Type: list(scope) | 
|  | # | 
|  | #     * name | 
|  | #       - Optional: A stable name for the library to use when publishing a | 
|  | #         zx_manifest. If omitted, soname is used. | 
|  | #       - Type: string | 
|  | # | 
|  | #     * soname | 
|  | #       - Required: `DT_SONAME` string in the ELF shared library. | 
|  | #       - Type: string | 
|  | # | 
|  | #     * dist | 
|  | #       - Required: File to load to satisfy $soname `DT_NEEDED` entries. | 
|  | #       - Type: path relative to `${toolchain_spec.lib_dir}` | 
|  | # | 
|  | #     * debug | 
|  | #       - Optional: Unstripped or separate debug file matching $dist. | 
|  | #       - Type: path relative to `${toolchain_spec.lib_dir}` | 
|  | # | 
|  | #     * breakpad | 
|  | #       - Required if `debug` is present and `toolchain.use_breakpad` is true: | 
|  | #         Path to breakpad .sym file. | 
|  | #       - Type: path relative to `${toolchain_spec.lib_dir}` | 
|  | # | 
|  |  | 
|  | # Used internally by clang_runtime_deps and rust_runtime_deps. | 
|  | # Define a group() target with the metadata matching a specific | 
|  | # set of runtime libraries. | 
|  | # | 
|  | # Args: | 
|  | #   entry [scope | bool] | 
|  | #      Either a runtime.json input scope, or the boolean value "false" | 
|  | #      to indicate an empty group. | 
|  | # | 
|  | #   libraries: [optional string list] | 
|  | #      An optional list of library names to embed | 
|  | #      in Fuchsia packages. If not provided, all runtime libraries from entry | 
|  | #      will be used. | 
|  | # | 
|  | #   rebased_toolchain_lib_dir [string] | 
|  | #      The rebased path to the toolchain's "/lib" sub-directory. | 
|  | # | 
|  | #   binary_common [scope] | 
|  | #      A scope containing common arguments for each entry in the | 
|  | #      final metadata.binaries list for the generated group(). | 
|  | # | 
|  | #   testonly, visibility | 
|  | #      Usual GN meaning. | 
|  | template("_define_runtime_group") { | 
|  | _rebased_lib_dir = invoker.rebased_toolchain_lib_dir | 
|  | _entry = invoker.entry | 
|  |  | 
|  | if (defined(invoker.libraries)) { | 
|  | _libraries = invoker.libraries | 
|  | } else { | 
|  | _libraries = [] | 
|  | } | 
|  |  | 
|  | _label = get_label_info(":$target_name", "label_with_toolchain") | 
|  |  | 
|  | # scope containing shared values for all entries in _binaries. | 
|  | _binary_base = { | 
|  | forward_variables_from(invoker.binary_common, "*") | 
|  |  | 
|  | cpu = current_cpu | 
|  | os = current_os | 
|  | label = _label | 
|  | type = "shared_library" | 
|  | } | 
|  |  | 
|  | _binaries = [] | 
|  | _distribution_entries = [] | 
|  | _debug_symbol_files = [] | 
|  |  | 
|  | if (_entry != false) { | 
|  | # Add all runtime libraries for this entry to metadata.binaries even | 
|  | # though they are not build outputs, as these are only used to upload the | 
|  | # corresponding symbol files to cloud storage. | 
|  | # See https://fxbug.dev/379848690 | 
|  | foreach(lib, _entry.runtime) { | 
|  | _dist_file = "${_rebased_lib_dir}/${lib.dist}" | 
|  |  | 
|  | _binaries += [ | 
|  | { | 
|  | forward_variables_from(_binary_base, "*") | 
|  | dist = _dist_file | 
|  | if (defined(lib.debug)) { | 
|  | debug = "${_rebased_lib_dir}/${lib.debug}" | 
|  | if (defined(lib.breakpad)) { | 
|  | breakpad = "${_rebased_lib_dir}/${lib.breakpad}" | 
|  | } | 
|  | } | 
|  | }, | 
|  | ] | 
|  |  | 
|  | if (defined(lib.debug)) { | 
|  | # Compute build-id from lib.debug if possible. Look for ..../.build-id/xx/yyyyyy.debug | 
|  | _build_id = "" | 
|  | _lib_debug_nosuffix = string_replace(lib.debug, ".debug", "") | 
|  | _has_debug_suffix = _lib_debug_nosuffix != lib.debug | 
|  | if (_has_debug_suffix) { | 
|  | _build_id_list = [] | 
|  | _build_id_list = string_split(_lib_debug_nosuffix, ".build-id/") | 
|  | _is_under_build_id = _build_id_list != [ _lib_debug_nosuffix ] | 
|  | if (_is_under_build_id) { | 
|  | _build_id = _build_id_list[1] | 
|  | _build_id = string_replace(_build_id, "/", "") | 
|  | } | 
|  | } | 
|  | _debug_symbol_files += [ | 
|  | { | 
|  | cpu = current_cpu | 
|  | os = current_os | 
|  | label = _label | 
|  | debug = "${_rebased_lib_dir}/${lib.debug}" | 
|  | if (_build_id != "") { | 
|  | elf_build_id = _build_id | 
|  | } | 
|  | if (defined(lib.breakpad)) { | 
|  | breakpad = "${_rebased_lib_dir}/${lib.breakpad}" | 
|  | } | 
|  | }, | 
|  | ] | 
|  | } | 
|  |  | 
|  | # On the other hand, only add entries to metadata.distribution_entries | 
|  | # for the libraries that really need to be packaged into dependent | 
|  | # Fuchsia packages. | 
|  | if (_libraries == [] || | 
|  | _libraries + [ lib.name ] - [ lib.name ] != _libraries) { | 
|  | _distribution_entries += [ | 
|  | { | 
|  | destination = "lib/${toolchain_variant.libprefix}${lib.soname}" | 
|  | label = _label | 
|  | source = _dist_file | 
|  | }, | 
|  | ] | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | # In many cases, the loop above will be empty. | 
|  | not_needed([ | 
|  | "_label", | 
|  | "_libraries", | 
|  | "_binary_base", | 
|  | "_rebased_lib_dir", | 
|  | ]) | 
|  |  | 
|  | group(target_name) { | 
|  | forward_variables_from(invoker, | 
|  | [ | 
|  | "testonly", | 
|  | "visibility", | 
|  | ]) | 
|  | metadata = { | 
|  | # Used by //:binaries build API module | 
|  | binaries = _binaries | 
|  |  | 
|  | # Used by distribution_manifest() template. | 
|  | distribution_entries = _distribution_entries | 
|  |  | 
|  | # Used by //:debug_symbols build API module. | 
|  | debug_symbol_files = _debug_symbol_files | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | # Define a group() target carrying the metadata related to the libraries | 
|  | # needed at runtime when linking against a static or shared version of libc++ | 
|  | # for the current build variant. | 
|  | # | 
|  | # Args: | 
|  | #    static_libcxx [bool]: Set to true for runtime dependencies of | 
|  | #       code linked with -static-libstdc++. | 
|  | # | 
|  | #    testonly, visibility: Usual GN meaning. | 
|  | # | 
|  | template("clang_runtime_deps") { | 
|  | if (toolchain_variant.with_shared && current_toolchain != shlib_toolchain) { | 
|  | group(target_name) { | 
|  | public_deps = [ ":$target_name($shlib_toolchain)" ] | 
|  | } | 
|  | not_needed(invoker, [ "static_libcxx" ]) | 
|  | } else { | 
|  | import("//build/config/clang/clang_prefix.gni") | 
|  | import("//build/config/clang/clang_toolchain_info.gni") | 
|  | import("//build/config/current_target_tuple.gni") | 
|  | import("//build/toolchain/zircon/clang.gni") | 
|  |  | 
|  | _variant_cflags = [] | 
|  | _variant_tags = toolchain_variant.tags | 
|  | if (_variant_tags + [ "asan" ] - [ "asan" ] != _variant_tags) { | 
|  | _variant_cflags = [ "-fsanitize=address" ] | 
|  | } else if (_variant_tags + [ "hwasan" ] - [ "hwasan" ] != _variant_tags) { | 
|  | _variant_cflags = [ "-fsanitize=hwaddress" ] | 
|  | } else if (_variant_tags + [ "ubsan" ] - [ "ubsan" ] != _variant_tags) { | 
|  | _variant_cflags = [ "-fsanitize=undefined" ] | 
|  | } | 
|  |  | 
|  | _variant_ldflags = [] | 
|  | if (invoker.static_libcxx) { | 
|  | _variant_ldflags = [ "-static-libstdc++" ] | 
|  | } | 
|  |  | 
|  | _target_tuple = current_target_tuple | 
|  |  | 
|  | # Find matching entry in runtime.json | 
|  | _entry = false | 
|  |  | 
|  | _clang_runtimes = clang_toolchain_info.runtimes | 
|  |  | 
|  | foreach(entry, _clang_runtimes) { | 
|  | if (entry.cflags == _variant_cflags && | 
|  | entry.ldflags == _variant_ldflags && | 
|  | entry.target + [ _target_tuple ] - [ _target_tuple ] != | 
|  | entry.target) { | 
|  | assert( | 
|  | _entry == false, | 
|  | "Multiple matches for cflags=${_variant_cflags}, ldflags=${_variant_ldflags} and ${_target_tuple} in runtime.json. File is ill-formed!") | 
|  | _entry = entry | 
|  | } | 
|  | } | 
|  |  | 
|  | _define_runtime_group(target_name) { | 
|  | forward_variables_from(invoker, | 
|  | [ | 
|  | "testonly", | 
|  | "visibility", | 
|  | ]) | 
|  | entry = _entry | 
|  | rebased_toolchain_lib_dir = "$rebased_clang_dir/lib" | 
|  | binary_common = { | 
|  | cflags = _variant_cflags | 
|  | ldflags = _variant_ldflags | 
|  | if (clang_version_string != "") { | 
|  | toolchain_id = clang_version_string | 
|  | } | 
|  | if (clang_version_description != "") { | 
|  | toolchain_version = clang_version_description | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | # Define a group() target carrying the metadata related to a Rust runtime | 
|  | # library. | 
|  | # | 
|  | # Args: | 
|  | #    name [string]: Library name prefix (e.g. "libstd" or "libtest"). | 
|  | #    shared_runtime [bool]: Set to true to specify the shared version of | 
|  | #       the runtime. | 
|  | # | 
|  | #    testonly, visibility: Usual GN meaning. | 
|  | # | 
|  | template("rust_runtime_deps") { | 
|  | if (toolchain_variant.with_shared && current_toolchain != shlib_toolchain) { | 
|  | group(target_name) { | 
|  | public_deps = [ ":$target_name($shlib_toolchain)" ] | 
|  | } | 
|  | not_needed(invoker, | 
|  | [ | 
|  | "name", | 
|  | "shared_runtime", | 
|  | ]) | 
|  | } else { | 
|  | import("//build/rust/config.gni") | 
|  |  | 
|  | if (invoker.shared_runtime) { | 
|  | _rustflags = [ "-Cprefer-dynamic" ] | 
|  | } else { | 
|  | _rustflags = [] | 
|  | } | 
|  |  | 
|  | _target_tuple = current_target_tuple | 
|  |  | 
|  | not_needed(invoker, [ "name" ]) | 
|  |  | 
|  | # Find matching entry in Rust runtime.json | 
|  | # This must use the same rustflags, target tuple and must contain | 
|  | # | 
|  | _entry = false | 
|  | foreach(entry, rustc_runtime) { | 
|  | if (entry.rustflags == _rustflags && entry.target + [ _target_tuple ] - | 
|  | [ _target_tuple ] != entry.target) { | 
|  | # Need to find a library in entry.runtime that matches invoker.name | 
|  | foreach(runtime, entry.runtime) { | 
|  | if (runtime.name == invoker.name) { | 
|  | assert( | 
|  | _entry == false, | 
|  | "Multiple matches for rustflags=${_rustflags} and ${_target_tuple} in rust runtime.json. File is ill-formed!") | 
|  | _entry = entry | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | _define_runtime_group(target_name) { | 
|  | forward_variables_from(invoker, | 
|  | [ | 
|  | "testonly", | 
|  | "visibility", | 
|  | ]) | 
|  | entry = _entry | 
|  | rebased_toolchain_lib_dir = rebase_path(rustc_lib_dir, root_build_dir) | 
|  | libraries = [ invoker.name ] | 
|  | binary_common = { | 
|  | rustflags = _rustflags | 
|  | if (rustc_version_string != "") { | 
|  | toolchain_id = rustc_version_string | 
|  | } | 
|  | if (rustc_version_description != "") { | 
|  | toolchain_version = rustc_version_description | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } |