| # 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/cpp/sdk_shared_library.gni") |
| import("//build/cpp/sdk_source_set.gni") |
| import("//build/cpp/sdk_static_library.gni") |
| import("//build/toolchain/toolchain_environment.gni") |
| |
| # LINT.IfChange |
| |
| # Build a zircon-specific library, possibly in several ways. |
| # |
| # This template should be used by Zircon build rules exclusively, and follows |
| # most of the conventions of the Zircon build `library()` template, which |
| # differ significantly from those of `library()` in the Fuchsia build. |
| # |
| # IMPORTANT NOTE: Due to historical reasons, its behaviour is very different, |
| # depending on the value of the `is_kernel` global variable. |
| # |
| # * When building with a Zircon-specific toolchain, it will create a source_set() |
| # if the global `is_kernel` is true (meaning building part of the kernel), or |
| # a static_library() target otherwise. The values of `public`, `sdk`, |
| # `sdk_area`, `sdk_headers`, `sdk_headers_for_internal_use`, `sdk_name`, |
| # `sdk_publishable`, and `stable` will be ignored entirely. |
| # |
| # This will also create a :headers sub-target, a group used to give access |
| # to the library's include directory from any dependent. Note that this |
| # does *not* make the library's headers, listed in `sdk_headers` public. |
| # |
| # This behaviour is needed to replicate the Zircon build's behaviour when |
| # compiling Zircon artefacts. |
| # |
| # * When not using a Zircon-specific toolchain, which means the library is built |
| # either as a Fuchsia user binary or a host binary, `sdk` must be set to determine |
| # the shape of the library, as must `sdk_headers to list the library's public |
| # headers, relative to its `include` sub-directory. |
| # |
| # If `sdk_publishable` is present, an sdk_*() template will be used, enabling |
| # the library to be part of the Fuchsia SDK. The value of `sdk_publishable` |
| # must be a valid SDK category. |
| # The only allowed value for new instances of this template is `"partner"`. |
| # This is enforced by the allowlists defined in //build/zircon/BUILD.gn. |
| # New libraries likely probably need to be added to the partner SDK rather |
| # than specifying one of the other SDK categories. See |
| # https://fxbug.dev/333125197 for details. |
| # |
| # Any ":<library>.as-needed" sub-targets that appear in `deps` will be |
| # rewritten into a dependency to the library itself, e.g.: |
| # |
| # deps = [ "//zircon/system/ulib/foo:foo.as-needed" ] |
| # |
| # will be replaced by: |
| # |
| # deps = [ "//zircon/system/ulib/foo:foo" ] |
| # |
| # Any ":headers" or ":<library>.headers" sub-targets that appear in |
| # `public_deps` will be rewritten into a dependency to the library itself, |
| # e.g.: |
| # |
| # public_deps = [ "//zircon/system/ulib/foo:headers" ] |
| # |
| # will be replaced by: |
| # |
| # public_deps = [ "//zircon/system/ulib/foo" ] |
| # |
| # Because the Fuchsia build doesn't support ":headers" sub-targets in |
| # non-kernel libraries for several technical reasons. |
| # |
| # Parameters |
| # |
| # sdk |
| # Optional: A value that indicates whether to build this library as a |
| # source set, static library or shared library with the Fuchsia build. |
| # This is required, except when building with Zircon-specific toolchains. |
| # Note that this name is confusing for historical reasons, because using |
| # this parameter does not alone make this library exported to the Fuchsia |
| # SDK (see `sdk_publishable` below for this). |
| # TODO(https://fxbug.dev/333125197): Rename this parameter. |
| # Values: "static" or "shared" or "source" |
| # |
| # sdk_publishable |
| # Optional: Indicates that this library can be added to the Fuchsia SDK |
| # and in which SDK category. |
| # TODO(https://fxbug.dev/333125197): Remove this parameter. |
| # Type: string indicating an SDK category. |
| # |
| # sdk_area (optional) |
| # [string] The API area responsible for maintaining this library. |
| # See //build/sdk/sdk_atom.gni. |
| # TODO(https://fxbug.dev/333125197): Remove this parameter. |
| # |
| # stable (optional) |
| # Whether this sdk_atom is stabilized. If false, an `.api` file will not be |
| # generated, and the atom will be marked as unstable in the final IDK. |
| # Required if `sdk == "source"` and `sdk_publishable` is specified and not |
| # "internal". Not allowed otherwise. |
| # TODO(https://fxbug.dev/333125197): Remove this parameter. |
| # |
| # public |
| # Optional: It or `sdk_headers` is required, except if the global |
| # `is_kernel` is true. Mutually exclusive with `sdk_headers`. |
| # This must list all the public header files for the library. |
| # Unlike `sdk_headers`, paths are not relative to `include/`. |
| # This is primarily used by bazel2gn-generated targets. |
| # |
| # sdk_headers |
| # Optional: It or `public` is required, except if the global |
| # `is_kernel` is true. Mutually exclusive with `public`. |
| # This must list all the public header files in the library's `include/` |
| # directory; names should be relative to `include/`. Despite the name, |
| # this parameter is not specific to SDK targets (those specifying |
| # `sdk_publishable`). |
| # TODO(https://fxbug.dev/333125197): Rename this parameter. |
| # Type: list(string) |
| # |
| # sdk_name |
| # Optional: Override the name of the library in the SDK. This can be used |
| # when `target_name` is already used by another SDK atom. |
| # Only allowed when `sdk_publishable` and `sdk == "source"` are specified. |
| # (For bazel2gn purposes, it is also allowed when `sdk_publishable` and |
| # (`sdk == "shared"` or `sdk == "static"`) are specified and its value is |
| # the same as `target_name`.) |
| # TODO(https://fxbug.dev/333125197): Remove this parameter. |
| # Type: string |
| # Default: `target_name` |
| # |
| # sdk_headers_for_internal_use |
| # Optional: This is always forwarded to the corresponding `sdk_*` template. |
| # See `sdk_source_set` for example about its significance. |
| # Unlike `sdk_headers`, names are not relative to `include/` so "include/" |
| # must be included in the path. |
| # TODO(https://fxbug.dev/333125197): Remove this parameter. |
| # |
| # api |
| # Path for the file representing the API of this library. |
| # This can be set when this template is used by a bazel2gn-generated target. |
| # It should only be set when the library is outside `//sdk/lib` and must |
| # match the default value for such libraries. |
| # |
| # See source_set() for other parameters. |
| # |
| template("zx_library") { |
| # Parameters that are not forwarded to the underlying target by default. |
| # They must be used or explicitly forwarded when appropriate. |
| # TODO(https://fxbug.dev/333125197): Remove when removing the parameters. |
| unforwarded_params = [ |
| "api", |
| "public", |
| "sdk", |
| "sdk_area", |
| "sdk_headers", |
| "sdk_headers_for_internal_use", |
| "sdk_name", |
| "sdk_publishable", |
| "stable", |
| ] |
| |
| assert(defined(invoker.public) != defined(invoker.sdk_headers), |
| "Exactly one of `public` and `sdk_headers` must be specified.") |
| |
| # Ensure SDK-specific parameters are only specified for libraries in the SDK. |
| # The following "sdk" parameters are always allowed: |
| # * `sdk` is required for the `zircon_toolchain=false` case. |
| # * `sdk_headers` is often used instead of "public". |
| assert(defined(invoker.sdk_publishable) || |
| (!defined(invoker.api) && !defined(invoker.sdk_area) && |
| !defined(invoker.sdk_headers_for_internal_use) && |
| !defined(invoker.sdk_name) && !defined(invoker.stable))) |
| |
| if (zircon_toolchain != false) { |
| _library_name = target_name |
| |
| if (toolchain_environment == "kernel") { |
| # In the kernel proper, zx_library() is always a source_set(). |
| # Everything goes into the kernel and anything unused gets linker GC. |
| kernel_library_target_type = "source_set" |
| } else { |
| kernel_library_target_type = "static_library" |
| } |
| |
| # If the library has the same name as its directory, just create |
| # :headers and :headers.config sub-targets. Otherwise, create |
| # :foo.headers and :foo.headers.config |
| if (get_label_info(":$_library_name", "name") == |
| get_path_info(get_label_info(":$_library_name", "dir"), "file")) { |
| _headers_target = "headers" |
| _headers_config_target = "headers.config" |
| } else { |
| _headers_target = "$_library_name.headers" |
| _headers_config_target = "$_library_name.headers.config" |
| } |
| |
| target(kernel_library_target_type, _library_name) { |
| if (kernel_library_target_type == "static_library") { |
| complete_static_lib = true |
| } |
| forward_variables_from(invoker, "*", unforwarded_params) |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| public_deps += [ ":$_headers_target" ] |
| } |
| |
| group(_headers_target) { |
| # Used to represent header dependencies. |
| # Direct use of public_configs should be rare but is sometimes needed. |
| forward_variables_from(invoker, |
| [ |
| "public_configs", |
| "public_deps", |
| "testonly", |
| "visibility", |
| ]) |
| if (!defined(public_configs)) { |
| public_configs = [] |
| } |
| public_configs += [ ":${_headers_config_target}" ] |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| public_deps += [ "//zircon/system/public" ] |
| } |
| |
| config(_headers_config_target) { |
| include_dirs = [ "include" ] |
| } |
| } else { |
| assert( |
| defined(invoker.sdk), |
| "The `sdk` argument is needed to build a zx_library() with a Fuchsia or host toolchain ($current_toolchain)") |
| shape = invoker.sdk |
| |
| sdkable = defined(invoker.sdk_publishable) |
| if (sdkable) { |
| assert( |
| invoker.sdk_publishable == "${invoker.sdk_publishable}", |
| "Must be an SDK category name if specified - received: ${invoker.sdk_publishable}") |
| sdk_category = invoker.sdk_publishable |
| } |
| assert((sdkable && shape == "source") || !defined(invoker.stable)) |
| |
| extra_target_args = { |
| } |
| if (shape == "source") { |
| if (sdkable) { |
| assert( |
| defined(invoker.stable) != |
| # TODO(https://fxbug.dev/331991540): Remove "firmware_sdk" once no longer used. |
| (sdk_category == "internal" || sdk_category == "firmware_sdk"), |
| "`stable` must be specified except for categories that are always unstable.") |
| if (defined(invoker.sdk_name)) { |
| name = invoker.sdk_name |
| } else { |
| name = target_name |
| } |
| target_type = "sdk_source_set" |
| extra_target_args = { |
| build_as_static = true |
| category = sdk_category |
| sdk_name = name |
| forward_variables_from(invoker, |
| [ |
| "sdk_headers_for_internal_use", |
| "sdk_area", |
| "stable", |
| ]) |
| } |
| } else { |
| target_type = "static_library" |
| assert(!defined(invoker.sdk_name)) |
| } |
| } else if (shape == "static") { |
| if (sdkable) { |
| assert(!defined(invoker.sdk_name) || invoker.sdk_name == target_name) |
| target_type = "sdk_static_library" |
| extra_target_args = { |
| category = sdk_category |
| sdk_name = target_name |
| libcxx_linkage = "static" |
| forward_variables_from(invoker, |
| [ |
| "sdk_headers_for_internal_use", |
| "sdk_area", |
| ]) |
| } |
| } else { |
| assert(!defined(invoker.sdk_name)) |
| target_type = "static_library" |
| } |
| } else if (shape == "shared") { |
| if (sdkable) { |
| assert(!defined(invoker.sdk_name) || invoker.sdk_name == target_name) |
| assert(sdk_category == "partner") |
| target_type = "sdk_shared_library" |
| extra_target_args = { |
| category = sdk_category |
| sdk_name = target_name |
| libcxx_linkage = "static" |
| forward_variables_from(invoker, |
| [ |
| "sdk_headers_for_internal_use", |
| "sdk_area", |
| ]) |
| } |
| } else { |
| assert(!defined(invoker.sdk_name)) |
| target_type = "shared_library" |
| } |
| } else { |
| assert(false, "Unknown library type: $shape") |
| } |
| |
| main_target_name = target_name |
| config_target_name = "$target_name.config" |
| |
| config(config_target_name) { |
| visibility = [ ":$main_target_name" ] |
| include_dirs = [ "include" ] |
| } |
| |
| # Ignore an "includes" parameter if it contains exactly the value above. |
| # This can happen when this template is used by a bazel2gn-generated target. |
| if (defined(invoker.includes) && invoker.includes == [ "include" ]) { |
| not_needed(invoker, [ "includes" ]) |
| } |
| |
| # IMPORTANT: Rewrite dependencies |
| |
| # ** Rewrite as-needed dependencies in `deps` ** |
| # |
| # Rewrite private dependencies on ".as-needed" targets into regular |
| # dependencies into the libraries themselves. For example: |
| # |
| # deps = [ "//src/zircon/lib/zircon:zircon.as-needed" ] |
| # |
| # will be replaced by: |
| # |
| # deps = [ "//src/zircon/lib/zircon:zircon(<same-toolchain>)" ] |
| # |
| # |
| # ** Rewrite header dependencies in `public_deps` ** |
| # |
| # For each zx_library(), the Zircon build used to produce a 'headers' |
| # group that adds a 'headers.config' public config. This is done to allow |
| # other targets to depend on the library's headers, but not the library |
| # itself. |
| # |
| # In practice, this means it is common for targets to list these headers |
| # groups in their public_deps, as in: |
| # |
| # public_deps = [ "//sdk/lib/fit:headers" ] |
| # |
| # However, these groups do not mix well with the Fuchsia build, and |
| # especially with sdk_source_set() or sdk_static_library(). |
| # |
| # To work around this, rewrite the headers public dependencies into |
| # regular dependencies into the libraries themselves. For example: |
| # |
| # public_deps = [ "//sdk/lib/fit:headers", "//sdk/lib/fit-promise:fit-promise.headers" ] |
| # |
| # will be replaced by: |
| # |
| # public_deps = [ "//sdk/lib/fit", "//sdk/lib/fit-promise:fit-promise" ] |
| # |
| lib_deps = [] |
| if (defined(invoker.deps)) { |
| # Rewrite any foo.as-needed deps to just foo. |
| foreach(label, invoker.deps) { |
| if (get_path_info(get_label_info(label, "name"), "extension") == |
| "as-needed") { |
| label = get_label_info(label, "dir") + ":" + |
| get_path_info(get_label_info(label, "name"), "name") + "(" + |
| get_label_info(label, "toolchain") + ")" |
| } |
| lib_deps += [ label ] |
| } |
| } |
| lib_public_deps = [] |
| if (defined(invoker.public_deps)) { |
| foreach(dep, invoker.public_deps) { |
| if (get_label_info(dep, "name") == "headers") { |
| # Format //zircon/.../foo:headers -> //zircon/.../foo |
| dep = get_label_info(dep, "dir") |
| } else if (get_path_info(get_label_info(dep, "name"), "extension") == |
| "headers") { |
| # Format //zircon/.../foo:bar.headers -> //zircon/.../foo:bar |
| dep = get_label_info(dep, "dir") + ":" + |
| get_path_info(get_label_info(dep, "name"), "name") |
| } |
| lib_public_deps += [ dep ] |
| } |
| } |
| |
| if (!is_fuchsia) { |
| lib_public_deps += [ "//zircon/system/public" ] |
| } |
| |
| _has_public_headers = |
| (defined(invoker.public) && invoker.public != []) || |
| (defined(invoker.sdk_headers) && invoker.sdk_headers != []) |
| |
| target(target_type, main_target_name) { |
| forward_variables_from(invoker, |
| "*", |
| unforwarded_params + [ |
| "deps", |
| "public_deps", |
| ]) |
| forward_variables_from(extra_target_args, "*") |
| |
| deps = lib_deps |
| public_deps = lib_public_deps |
| |
| if (sdkable && sdk_category == "partner") { |
| target_path = get_label_info(target_name, "label_no_toolchain") |
| is_in_sdk_dir = target_path == |
| "//sdk/" + string_replace(target_path, "//sdk/", "", 1) |
| if (!is_in_sdk_dir) { |
| # For targets outside `//sdk` that require modification |
| # acknowledgement, override the default `.api` file location with |
| # one under `//sdk/lib`. |
| api = "//sdk/lib/$target_name/$target_name.api" |
| |
| # bazel2gn may generate "api". Ignore it after confirming it matches. |
| if (defined(invoker.api)) { |
| assert(api == invoker.api, api) |
| } |
| } |
| } |
| |
| if (_has_public_headers) { |
| if (defined(invoker.public)) { |
| public = invoker.public |
| } else { |
| public = [] |
| foreach(header, invoker.sdk_headers) { |
| public += [ "include/$header" ] |
| } |
| } |
| } |
| |
| if (!defined(public_configs)) { |
| public_configs = [] |
| } |
| public_configs += [ ":$config_target_name" ] |
| |
| if (!defined(defines)) { |
| defines = [] |
| } |
| defines += [ "_ALL_SOURCE" ] |
| |
| if (!defined(data_deps)) { |
| data_deps = [] |
| } |
| |
| # Add allowlist to data_deps rather than deps to not trigger SDK deps |
| # logic |
| data_deps += [ "//build:deprecated_zx_wrapper_allowlist" ] |
| if (sdkable) { |
| # Prevent additional confusing uses of `sdk_publishable` per its |
| # documentation. |
| if (sdk_category == "partner") { |
| data_deps += [ "//build/zircon:sdk_category_partner_allowlist" ] |
| } else if (sdk_category == "internal") { |
| data_deps += [ "//build/zircon:sdk_category_internal_allowlist" ] |
| } else if (sdk_category == "firmware_sdk") { |
| data_deps += [ "//build/zircon:sdk_category_firmware_allowlist" ] |
| } else { |
| assert( |
| false, |
| "Unsupported SDK category '${sdk_category}' - see https://fxbug.dev/333125197.") |
| } |
| } |
| } |
| } |
| |
| # Uncomment the below to generate the allowlist |
| #print("\"" + get_label_info(":$target_name", "dir") + "/*\",") |
| } |
| |
| set_defaults("zx_library") { |
| configs = default_common_binary_configs |
| } |
| # LINT.ThenChange(//build/bazel/rules/idk/private/idk_cc_prebuilt_library.bzl, |
| # //build/bazel/rules/idk/private/idk_cc_source_library.bzl, |
| # //build/bazel/rules/zx_library.bzl) |