| # 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") |
| |
| # 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 `sdk`, `sdk_publishable` |
| # and `sdk_headers` 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 :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. |
| # Type: string indicating an SDK category. |
| # |
| # sdk_area (optional) |
| # [string] The API area responsible for maintaining this library. |
| # See //build/sdk/sdk_atom.gni. |
| # |
| # stable (optional) |
| # Note: this option only currently used if sdk == "source"' |
| # Whether this sdk_atom is stabilized. If false, there will not be |
| # .api file generated, and the atom will be marked as unstable in the final |
| # IDK. |
| # Defaults to false. |
| # |
| # sdk_headers |
| # Optional: Required, except if the global `is_kernel` is true. |
| # This must list all the public header files in the library's `include/` |
| # directory; names should be relative to `include/`. |
| # Type: list(string) |
| # |
| # sdk_name |
| # Optional: Name under which the library is published. This can be used |
| # when $target_name is already used by another target in the Fuchsia build. |
| # 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. |
| # |
| # See source_set() for other parameters. |
| # |
| template("zx_library") { |
| template_params = [ |
| "sdk", |
| "sdk_headers", |
| "sdk_publishable", |
| "stable", |
| ] |
| |
| # TODO(https://fxbug.dev/333125197): Move this such that it is only applied |
| # when needed and does not silently ignore parameters that will never be used |
| # (i.e., for non-sdkable targets). Update the documentation above to indicate |
| # when it is supported. |
| not_needed(invoker, |
| [ |
| "sdk_name", |
| |
| # Not all template expansion paths use this variable, don't |
| # error out in those paths. |
| "sdk_headers_for_internal_use", |
| ]) |
| |
| 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, "*", template_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 |
| } |
| |
| extra_target_args = { |
| } |
| if (shape == "source") { |
| if (sdkable) { |
| name = target_name |
| if (defined(invoker.sdk_name)) { |
| name = invoker.sdk_name |
| } |
| target_type = "sdk_source_set" |
| extra_target_args = { |
| api = "//sdk/lib/$target_name/$target_name.api" |
| 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" |
| } |
| } else if (shape == "static") { |
| if (sdkable) { |
| target_type = "sdk_static_library" |
| if (sdk_category == "public" || sdk_category == "partner") { |
| extra_target_args = { |
| api = "//sdk/lib/$target_name/$target_name.api" |
| category = sdk_category |
| libcxx_linkage = "static" |
| sdk_name = target_name |
| forward_variables_from(invoker, |
| [ |
| "sdk_headers_for_internal_use", |
| "sdk_area", |
| ]) |
| } |
| } else { |
| 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 { |
| target_type = "static_library" |
| } |
| } else if (shape == "shared") { |
| if (sdkable) { |
| target_type = "sdk_shared_library" |
| if (sdk_category == "public" || sdk_category == "partner") { |
| extra_target_args = { |
| api = "//sdk/lib/$target_name/$target_name.api" |
| category = sdk_category |
| libcxx_linkage = "static" |
| sdk_name = target_name |
| symbols_api = "//sdk/lib/$target_name/$target_name.ifs" |
| forward_variables_from(invoker, |
| [ |
| "sdk_headers_for_internal_use", |
| "sdk_area", |
| ]) |
| } |
| } else { |
| 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 { |
| 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" ] |
| } |
| |
| # IMPORTANT: 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. |
| # |
| 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 ] |
| } |
| } |
| |
| # Remove references to a libzircon dependency, as it is provided by the |
| # sysroot in the present build. |
| |
| lib_libs = [] |
| if (defined(invoker.libs)) { |
| lib_libs = invoker.libs |
| } |
| |
| if (!is_fuchsia) { |
| lib_public_deps += [ "//zircon/system/public" ] |
| } |
| |
| _has_public_headers = |
| defined(invoker.sdk_headers) && invoker.sdk_headers != [] |
| |
| target(target_type, main_target_name) { |
| forward_variables_from(invoker, |
| "*", |
| template_params + [ |
| "deps", |
| "libs", |
| "public_deps", |
| ]) |
| |
| deps = lib_deps |
| libs = lib_libs |
| public_deps = lib_public_deps |
| |
| forward_variables_from(extra_target_args, "*") |
| |
| if (_has_public_headers) { |
| public = [] |
| foreach(header, invoker.sdk_headers) { |
| public += [ "include/$header" ] |
| } |
| if (sdkable && sdk_category == "internal") { |
| # By default, templates like sdk_source_set() set the `include_base` value to "//" for |
| # targets in the 'internal' category. Set if to the correct value here to avoid |
| # issues later when trying to use the library from the SDK. |
| # See https://fxbug.dev/42066095 for details. |
| include_base = "include" |
| } |
| } |
| |
| 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 == "cts") { |
| data_deps += [ "//build/zircon:sdk_category_cts_allowlist" ] |
| } else if (sdk_category == "excluded") { |
| data_deps += [ "//build/zircon:sdk_category_excluded_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 |
| } |