| # Copyright 2017 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/board.gni") |
| import("//build/cmx/cmx.gni") |
| import("//build/compiled_action.gni") |
| import("//build/images/boot.gni") |
| import("//build/images/manifest.gni") |
| import("//build/json/validate_json.gni") |
| import("//build/package/component.gni") |
| import("//build/testing/test_spec.gni") |
| |
| # Generate a list of package metadata exported from all packages in the |
| # transitive closure of declared dependencies, with an implied barrier at each |
| # package (dependency chains cease processing at package targets). |
| # |
| # Parameters |
| # |
| # data_keys (required) |
| # [list of strings] A list of package target metadata keys to collect into a |
| # list. See gn help for data_keys for more information. |
| # |
| # Well known package metadata: |
| # |
| # snapshot_entries |
| # The snapshot entries are consumed for the production of the snapshots |
| # that feed into `fx delta` for version to version OTA size computations. |
| # |
| # blob_manifests |
| # The blob manifests are aggregated by the image build process to produce |
| # manifests to publish to repositories and to produce manifests to write |
| # into blobfs images. |
| # |
| # meta_far_index_entries |
| # The metafar index entries are aggregated in image builds to produce |
| # manifests of packages to publish to a repository. |
| # |
| # meta_far_merkle_index_entries |
| # The metafar merkle index entries are aggregated in image builds to |
| # produce package server indices for base serving. |
| # |
| # package_output_manifests |
| # The path of each output manifest for each package. |
| # |
| # package_barrier |
| # [list of labels] This is passed to walk_keys and can be used as a barrier to |
| # control dependency propgatation below a package target. |
| # |
| # data_deps (optional) |
| # deps (optional) |
| # metadata (optional) |
| # output_conversion (optional) |
| # outputs (optional) |
| # public_deps (optional) |
| # rebase (optional) |
| # testonly (optional) |
| # visibility (optional) |
| # Same as for any GN `generated_file()` target. |
| template("package_metadata_list") { |
| generated_file(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "data_keys", |
| "deps", |
| "metadata", |
| "output_conversion", |
| "outputs", |
| "public_deps", |
| "rebase", |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (!defined(outputs)) { |
| outputs = [ |
| target_gen_dir + "/" + target_name, |
| ] |
| } |
| |
| walk_keys = [ "package_barrier" ] |
| } |
| } |
| |
| # Generate a list of fuchsia-pkg URLs for component from all packages in the |
| # transitive closure of declared dependencies, with an implied barrier at each |
| # package (dependency chains cease processing at package targets). |
| # |
| # Parameters |
| # |
| # data_deps (optional) |
| # deps (optional) |
| # outputs (optional) |
| # public_deps (optional) |
| # testonly (optional) |
| # visibility (optional) |
| # Same as for any GN `generated_file()` target. |
| template("component_index_metadata_list") { |
| generated_file(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "deps", |
| "outputs", |
| "public_deps", |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (!defined(outputs)) { |
| outputs = [ |
| target_gen_dir + "/" + target_name, |
| ] |
| } |
| |
| data_keys = [ "component_index" ] |
| walk_keys = [ "component_index_barrier" ] |
| } |
| } |
| |
| # Generate a sealed package file from a manifest. |
| # |
| # Parameters |
| # |
| # manifest (required) |
| # [label] A generate_manifest() target defined earlier in the same file. |
| # This provides the contents for the package. |
| # |
| # The following two items are only required in order to produce metadata about |
| # the package sets, and may be removed in the future: |
| # |
| # package_name (required) |
| # [string] Name of the package (should match what is in meta/package) |
| # package_variant (default: "0") |
| # [string] Variant of the package (should match what is in meta/package) |
| # |
| # deps (optional) |
| # test (optional) |
| # visibility (optional) |
| # Same as for any GN `action()` target. |
| |
| template("pm_build_package") { |
| compiled_action(target_name) { |
| tool = "//garnet/go/src/pm:pm_bin" |
| tool_output_name = "pm" |
| |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "deps", |
| "public_deps", |
| "testonly", |
| "visibility", |
| "package_name", |
| "package_variant", |
| ]) |
| if (!defined(deps)) { |
| deps = [] |
| } |
| pkg_manifest_outputs = get_target_outputs(invoker.manifest) |
| pkg_manifest_file = pkg_manifest_outputs[0] |
| pkg_out_dir = "$target_out_dir/$target_name" |
| |
| if (!defined(package_variant)) { |
| package_variant = "0" |
| } |
| |
| assert(defined(package_name), "A package name is required") |
| assert(package_name != "", "A package name is required") |
| |
| deps += [ invoker.manifest ] |
| |
| inputs = [ |
| pkg_manifest_file, |
| ] |
| |
| depfile = "$pkg_out_dir/meta.far.d" |
| |
| pkg_output_manifest = "$pkg_out_dir/package_manifest.json" |
| outputs = [ |
| # produced by seal, must be listed first because of depfile rules. |
| "$pkg_out_dir/meta.far", |
| |
| # update |
| "$pkg_out_dir/meta/contents", |
| |
| # seal |
| "$pkg_out_dir/meta.far.merkle", |
| |
| # package blob json manifest |
| "$pkg_out_dir/blobs.json", |
| |
| # package blob manifest |
| "$pkg_out_dir/blobs.manifest", |
| |
| # package output manifest |
| pkg_output_manifest, |
| ] |
| |
| blobs_json_path = rebase_path("${pkg_out_dir}/blobs.json", root_build_dir) |
| |
| # Package metadata must be kept in sync between package.gni and |
| # prebuilt_package.gni. The template package_metadata_list in package.gni |
| # documents the fields required to be implemented by both templates. |
| metadata = { |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| |
| # We only ever want to collect the following package manifests from |
| # packages, not from dependencies of packages, so the barrier prevents us |
| # from walking any further in the dependency chain. See `gn help |
| # walk_keys` for more information on the mechanic. |
| package_barrier = [] |
| |
| package_names = [ package_name ] |
| |
| snapshot_entries = [ "$package_name/$package_variant=$blobs_json_path" ] |
| |
| blob_manifests = |
| [ rebase_path("$pkg_out_dir/blobs.manifest", root_build_dir) ] |
| |
| meta_far_index_entries = |
| [ "$package_name/$package_variant=" + |
| rebase_path("$pkg_out_dir/meta.far", root_build_dir) ] |
| |
| meta_far_merkle_index_entries = |
| [ "$package_name/$package_variant=" + |
| rebase_path("$pkg_out_dir/meta.far.merkle", root_build_dir) ] |
| |
| package_output_manifests = [ pkg_output_manifest ] |
| } |
| |
| args = [ |
| "-o", |
| rebase_path(pkg_out_dir, root_build_dir), |
| "-m", |
| rebase_path(pkg_manifest_file, root_build_dir), |
| "-n", |
| package_name, |
| "-version", |
| package_variant, |
| "build", |
| "-output-package-manifest", |
| rebase_path(pkg_output_manifest, root_build_dir), |
| "-depfile", |
| "-blobsfile", |
| "-blobs-manifest", |
| ] |
| } |
| } |
| |
| # Defines a package |
| # |
| # The package template is used to define a unit of related code and data. |
| # A package always has a name (defaulting to the target name) and lists of |
| # scopes describing the components of the package. |
| # |
| # Parameters |
| # |
| # deprecated_system_image (optional, default `false`) |
| # [bool] If true, the package is stored in the /system filesystem image |
| # rather than in a Fuchsia package. |
| # |
| # TODO(PKG-46): Will be removed entirely eventually. |
| # |
| # If this package uses the `drivers` parameter, |
| # `deprecated_system_image` must be set to `true` because we are not |
| # yet sophisticated enough to load drivers out of packages. |
| # |
| # meta (optional) |
| # [list of scopes] Defines the metadata entries in the package. A metadata |
| # entry is typically a source file and is placed in the `meta/` directory of |
| # the assembled package. |
| # |
| # Requires `deprecated_system_image` to be `false`. |
| # |
| # Entries in a scope in the meta list: |
| # |
| # path (required) |
| # [path] Location of entry in source or build directory. If the |
| # resource is checked in, this will typically be specified as a |
| # path relative to the BUILD.gn file containing the `package()` |
| # target. If the resource is generated, this will typically be |
| # specified relative to `$target_gen_dir`. |
| # |
| # dest (required) |
| # [path] Location the resource will be placed within `meta/`. |
| # |
| # binary (optional, *DEPRECATED*) |
| # [string] The path to the primary binary for the package, relative to |
| # `$root_out_dir`. The binary will be placed in the assembled package at |
| # `bin/app` and will be executed by default when running the package. |
| # |
| # Requires `deprecated_system_image` to be `false`. |
| # |
| # binaries (optional) |
| # [list of scopes] Defines the binaries in the package. A binary is |
| # typically produced by the build system and is placed in the `bin/` |
| # directory of the assembled package. |
| # |
| # Entries in a scope in the binaries list: |
| # |
| # name (required) |
| # [string] Name of the binary. |
| # |
| # source (optional) |
| # [path] Location of the binary in the build directory if it is not |
| # at `$root_out_dir/$name`. |
| # |
| # dest (optional) |
| # [path] Location the binary will be placed within `bin/`. |
| # |
| # shell (optional) |
| # [boolean] (default: false) When true, the binary is runnable from the shell. |
| # Shell binaries are run in the shell namespace and are not run as components. |
| # |
| # components (optional) |
| # [list of fuchsia_component targets] Defines all the components this |
| # package should include in assembled package. |
| # |
| # Requires `deprecated_system_image` to be `false`. |
| # |
| # tests (optional) |
| # [list of scopes] Defines the test binaries in the package. A test is |
| # typically produced by the build system and is placed in the `test/` |
| # directory of the assembled package. |
| # |
| # Entries in a scope in the tests list: |
| # |
| # name (required) |
| # [string] Name of the test. |
| # |
| # dest (optional, default: name) |
| # [path] Location the binary will be placed within `test/`. |
| # |
| # disabled (optional) |
| # [bool] Whether to disable the test on continuous integration |
| # jobs. This can be used when a test is temporarily broken, or if |
| # it is too flaky or slow for CI. The test will also be skipped by |
| # the `runtests` command. |
| # |
| # environments (optional, default: [ { dimensions = { device_type = "QEMU" } } ]) |
| # [list of scopes] Device environments in which the test should run. |
| # |
| # Each scope in $environments contains: |
| # |
| # dimensions (required) |
| # [scope] Dimensions of bots to target. Valid dimensions are |
| # element-wise subsets of the test platform entries defined in |
| # //build/testing/platforms.gni. |
| # |
| # tags (optional) |
| # [list of strings] Keys on which tests may be grouped. Tests with |
| # given keys will be run (1) together, and (2) only with support |
| # from the Infrastructure team. Labels are used as an escape hatch |
| # from the default testing pipeline for special tests or environments. |
| # |
| # drivers (optional) |
| # [list of scopes] Defines the drivers in the package. A driver is |
| # typically produced by the build system and is placed in the `driver/` |
| # directory of the assembled package. |
| # |
| # Requires `deprecated_system_image` to be `true`. |
| # |
| # Entries in a scope in the drivers list: |
| # |
| # name (required) |
| # [string] Name of the driver. |
| # |
| # loadable_modules (optional) |
| # [list of scopes] Defines the loadable modules in the package. These |
| # are produced by `loadable_module()` GN targets, and are typically |
| # placed in the `lib/` directory of the assembled packaged. |
| # |
| # Entries in a scope in the loadable_modules list: |
| # |
| # name (required) |
| # [string] Name of the loadable_module. |
| # |
| # dest (optional, default: "lib") |
| # [string] Location the binary will be placed in the package. |
| # |
| # libraries (optional, *DEPRECATED*) |
| # [list of scopes] Defines the (shared) libraries in the package. A library |
| # is placed in the `lib/` directory of the assembled package. |
| # |
| # This is deprecated but is necessary in some `system_image` packages |
| # that install libraries used by things that don't properly isolate |
| # their dependencies. Do not use it unless you are sure you have to. |
| # |
| # Entries in a scope in the libraries list: |
| # |
| # name (required) |
| # [string] Name of the library |
| # |
| # source (optional) |
| # [path] Location of the binary in the build directory if it is not at |
| # `$root_out_dir/$name` |
| # |
| # dest (optional) |
| # [path] Location the binary will be placed within `lib/` |
| # |
| # resources (optional) |
| # [list of scopes] Defines the resources in the package. A resource is a |
| # data file that may be produced by the build system, checked in to a |
| # source repository, or produced by another system that runs before the |
| # build. Resources are placed in the `data/` directory of the assembled |
| # package. |
| # |
| # Entries in a scope in the resources list: |
| # |
| # path (required) |
| # [path] Location of resource in source or build directory. If the |
| # resource is checked in, this will typically be specified as a |
| # path relative to the BUILD.gn file containing the `package()` |
| # target. If the resource is generated, this will typically be |
| # specified relative to `$target_gen_dir`. |
| # |
| # dest (required) |
| # [path] Location the resource will be placed within `data/`. |
| # |
| # extra (optional) |
| # [list of paths] Manifest files containing extra entries, which |
| # might be generated by the build. |
| # |
| # deps (optional) |
| # public_deps (optional) |
| # data_deps (optional) |
| # testonly (optional) |
| # Usual GN meanings. |
| # |
| template("package") { |
| if (current_toolchain == target_toolchain) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| pkg_target_name = target_name |
| pkg = { |
| package_version = "0" # placeholder |
| forward_variables_from(invoker, |
| [ |
| "binaries", |
| "binary", |
| "components", |
| "data_deps", |
| "deprecated_misc_storage", |
| "deprecated_shell", |
| "deprecated_system_image", |
| "deps", |
| "global_data", |
| "public_deps", |
| "drivers", |
| "extra", |
| "libraries", |
| "loadable_modules", |
| "meta", |
| "package_name", |
| "resources", |
| "rootjob_svc", |
| "rootresource_svc", |
| "visibility", |
| "tests", |
| ]) |
| if (!defined(binaries)) { |
| binaries = [] |
| } |
| if (!defined(deprecated_system_image)) { |
| deprecated_system_image = false |
| } |
| if (!defined(deps)) { |
| deps = [] |
| } |
| if (!defined(components)) { |
| components = [] |
| } |
| if (!defined(data_deps)) { |
| data_deps = [] |
| } |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| if (!defined(extra)) { |
| extra = [] |
| } |
| if (!defined(drivers)) { |
| drivers = [] |
| } |
| if (!defined(loadable_modules)) { |
| loadable_modules = [] |
| } |
| if (!defined(libraries)) { |
| libraries = [] |
| } |
| if (!defined(meta)) { |
| meta = [] |
| } |
| if (!defined(package_name)) { |
| package_name = pkg_target_name |
| } |
| foreach(component, components) { |
| deps += [ component ] |
| } |
| if (!defined(resources)) { |
| resources = [] |
| } |
| if (!defined(tests)) { |
| tests = [] |
| } |
| } |
| |
| assert(pkg.package_name != "tests" && pkg.package_name != "app" && |
| pkg.package_name != "bin" && pkg.package_name != "pkg" && |
| pkg.package_name != "lib" && pkg.package_name != "package" && |
| pkg.package_name != "binary" && pkg.package_name != "service" && |
| pkg.package_name != "svc" && pkg.package_name != "component", |
| "${pkg.package_name} is too generic a name for a package") |
| |
| pkg_label = get_label_info(":$pkg_target_name", "label_no_toolchain") |
| pkg_desc = "Package ${pkg_label} (${pkg.package_name}):" |
| if (pkg.deprecated_system_image) { |
| assert(pkg.meta == [], |
| "$pkg_desc deprecated_system_image incompatible with meta") |
| assert(pkg.components == [], |
| "$pkg_desc deprecated_system_image incompatible with components") |
| assert(!defined(pkg.binary), |
| "$pkg_desc deprecated_system_image incompatible with binary") |
| |
| # Only appmgr can contribute binaries to /system/bin. |
| assert(pkg.binaries == [] || pkg.package_name == "appmgr", |
| "no new packages are allowed to add binaries to /system/bin") |
| |
| assert(pkg.tests == [], "tests are not allowed in /system") |
| } else { |
| assert(pkg.drivers == [], |
| "$pkg_desc drivers requires deprecated_system_image") |
| assert(pkg.libraries == [], |
| "$pkg_desc libraries requires deprecated_system_image") |
| if (defined(pkg.binary)) { |
| pkg.binaries += [ |
| { |
| name = "app" |
| source = pkg.binary |
| }, |
| ] |
| } |
| } |
| |
| # Validate .cmx files |
| foreach(meta, pkg.meta) { |
| if (get_path_info(meta.dest, "extension") == "cmx") { |
| validate = "validate_" + pkg_target_name + "_" + |
| get_path_info(meta.dest, "file") |
| cmx_validate(validate) { |
| data = meta.path |
| |
| # the cmx file may be generated by one of this package's dependencies, |
| # but we don't know which one, so depend on all package deps here. |
| deps = pkg.deps |
| public_deps = pkg.public_deps |
| extra_schemas = [] |
| |
| # Remove this validation when the "deprecated-misc-storage" feature is removed. |
| if (!defined(pkg.deprecated_misc_storage)) { |
| extra_schemas += [ |
| { |
| schema = "//build/cmx/block_deprecated_misc_storage.json" |
| error_msg = "The 'deprecated-misc-storage' feature is deprecated and guarded by an allowlist." |
| }, |
| ] |
| } |
| |
| # TODO(jseibert): Remove this validation when the "deprecated-shell" feature is removed. |
| if (!defined(pkg.deprecated_shell)) { |
| extra_schemas += [ |
| { |
| schema = "//build/cmx/block_deprecated_shell.json" |
| error_msg = "The 'deprecated-shell' feature is deprecated and guarded by an allowlist." |
| }, |
| ] |
| } |
| |
| if (!defined(pkg.rootjob_svc)) { |
| extra_schemas += [ |
| { |
| schema = "//build/cmx/block_rootjob_svc.json" |
| error_msg = "The 'fuchsia.boot.RootJob' service is guarded by an allowlist." |
| }, |
| ] |
| } |
| if (!defined(pkg.rootresource_svc)) { |
| extra_schemas += [ |
| { |
| schema = "//build/cmx/block_rootresource_svc.json" |
| error_msg = "The 'fuchsia.boot.RootResource' service is guarded by an allowlist." |
| }, |
| ] |
| } |
| } |
| |
| pkg.deps += [ ":$validate" ] |
| } |
| } |
| |
| # TODO: this doesn't handle the case where the profile variant is enabled only for |
| # a single target rather than the entire build. |
| needs_debugdata = |
| select_variant + [ "profile" ] - [ "profile" ] != select_variant |
| not_needed([ "needs_debugdata" ]) |
| |
| # cmx_format will minify cmx files in non-debug builds, and pretty-print cmx |
| # files in debug builds |
| formatted_manifest = [] |
| component_indices = [] |
| foreach(meta, pkg.meta) { |
| if (get_path_info(meta.dest, "extension") == "cmx") { |
| manifest_deps = [] |
| manifest_deps = pkg.deps |
| manifest_path = meta.path |
| |
| if (needs_debugdata) { |
| merge_target = "debugdata_" + pkg_target_name + "_" + |
| get_path_info(meta.dest, "file") |
| cmx_merge(merge_target) { |
| sources = [ |
| rebase_path(meta.path), |
| rebase_path("//build/config/sanitizers/debugdata.cmx"), |
| ] |
| deps = pkg.deps |
| } |
| manifest_deps += [ ":${merge_target}" ] |
| merged_outputs = [] |
| merged_outputs = get_target_outputs(":${merge_target}") |
| manifest_path = merged_outputs[0] |
| } |
| |
| if (defined(pkg.global_data)) { |
| merge_target = "global_data_" + pkg_target_name + "_" + |
| get_path_info(meta.dest, "file") |
| cmx_merge(merge_target) { |
| sources = [ |
| rebase_path(meta.path), |
| rebase_path("//build/cmx/internal_allow_global_data.cmx"), |
| ] |
| deps = pkg.deps |
| } |
| manifest_deps += [ ":${merge_target}" ] |
| merged_outputs = [] |
| merged_outputs = get_target_outputs(":${merge_target}") |
| manifest_path = merged_outputs[0] |
| } |
| |
| component_indices += [ "fuchsia-pkg://fuchsia.com/" + pkg.package_name + |
| "#meta/" + meta.dest ] |
| format = |
| "format_" + pkg_target_name + "_" + get_path_info(meta.dest, "file") |
| cmx_format(format) { |
| data = rebase_path(manifest_path) |
| deps = manifest_deps |
| } |
| formatted_outputs = [] |
| formatted_outputs = get_target_outputs(":$format") |
| meta.path = formatted_outputs[0] |
| pkg.deps += [ ":$format" ] |
| } else if (get_path_info(meta.path, "extension") == "cml") { |
| component_indices += [ "fuchsia-pkg://fuchsia.com/" + pkg.package_name + |
| "#meta/" + meta.dest ] |
| compiled = "compiled_" + pkg_target_name + "_" + |
| get_path_info(meta.dest, "file") |
| |
| cm_compile(compiled) { |
| data = rebase_path(meta.path) |
| deps = pkg.deps |
| public_deps = pkg.public_deps |
| } |
| pkg.deps += [ ":$compiled" ] |
| compiled_outputs = [] |
| compiled_outputs = get_target_outputs(":$compiled") |
| meta.path = compiled_outputs[0] |
| } |
| formatted_manifest += [ meta ] |
| } |
| |
| # Collect the package's primary manifest. For a system_image package, |
| # this is its contributions to the /system manifest. For an isolated |
| # package, this is the manifest for the package's `pkg/` filesystem. |
| pkg_manifest = [] |
| foreach(meta, formatted_manifest) { |
| pkg_manifest += [ |
| { |
| dest = "meta/${meta.dest}" |
| source = rebase_path(meta.path) |
| }, |
| ] |
| } |
| shell_binaries = [] |
| foreach(binary, pkg.binaries) { |
| if (defined(binary.dest)) { |
| dest = binary.dest |
| } else { |
| dest = binary.name |
| } |
| dest = "bin/${dest}" |
| |
| if (defined(binary.shell) && binary.shell) { |
| shellfile = target_gen_dir + "/" + dest + ".shell" |
| write_file( |
| shellfile, |
| [ "#!resolve fuchsia-pkg://fuchsia.com/${pkg.package_name}#${dest}" ]) |
| shell_binaries += |
| [ "${dest}=" + rebase_path(shellfile, root_build_dir) ] |
| } |
| |
| pkg_manifest += [ |
| { |
| dest = dest |
| |
| if (defined(binary.source)) { |
| source = binary.source |
| } else { |
| source = binary.name |
| } |
| source = rebase_path(source, "", root_out_dir) |
| }, |
| ] |
| } |
| |
| foreach(test, pkg.tests) { |
| is_disabled = defined(test.disabled) && test.disabled |
| |
| if (defined(test.dest)) { |
| dest = test.dest |
| } else { |
| dest = test.name |
| } |
| if (is_disabled) { |
| dest = "disabled/${dest}" |
| } |
| |
| if (bootfs_only) { |
| url_scheme_and_host = "fuchsia-boot://" |
| url_pkg_name = "" |
| dest = "test/sys/$dest" |
| path = "/boot/$dest" |
| } else { |
| url_scheme_and_host = "fuchsia-pkg://fuchsia.com" |
| dest = "test/$dest" |
| if (pkg.deprecated_system_image) { |
| url_pkg_name = "system" |
| path = "/system/$dest" |
| } else { |
| url_pkg_name = pkg.package_name |
| path = |
| "/pkgfs/packages/${pkg.package_name}/${pkg.package_version}/$dest" |
| } |
| } |
| |
| url_resource_path = dest |
| dest_name = get_path_info(dest, "name") |
| not_needed([ "dest_name" ]) |
| |
| # Check that all tests are components with cmx/cm files at the expected path. |
| if (!pkg.deprecated_system_image && !bootfs_only && !is_disabled && |
| (!defined(require_bare_tests_allowlist) || |
| !require_bare_tests_allowlist)) { |
| require_bare_tests_allowlist = true |
| foreach(meta, pkg.meta) { |
| extension = get_path_info(meta.dest, "extension") |
| if (extension == "cmx" || extension == "cm") { |
| meta_name = get_path_info(meta.dest, "name") |
| if (dest_name == meta_name) { |
| require_bare_tests_allowlist = false |
| url_resource_path = "meta/${meta.dest}" |
| } |
| } |
| } |
| } |
| |
| url = "${url_scheme_and_host}/${url_pkg_name}#${url_resource_path}" |
| |
| if (!is_disabled) { |
| test_spec_name = "${pkg.package_name}_${dest}_test_spec" |
| main_target_name = target_name |
| pkg.deps += [ ":$test_spec_name" ] |
| |
| test_spec(test_spec_name) { |
| name = test.name |
| target = main_target_name |
| path = path |
| package_url = url |
| forward_variables_from(test, [ "environments" ]) |
| } |
| } else { |
| not_needed([ |
| "path", |
| "url", |
| ]) |
| } |
| |
| pkg_manifest += [ |
| { |
| dest = dest |
| source = rebase_path(test.name, "", root_out_dir) |
| }, |
| ] |
| } |
| |
| foreach(module, pkg.loadable_modules) { |
| pkg_manifest += [ |
| { |
| if (defined(module.dest)) { |
| dest = module.dest |
| } else { |
| dest = "lib" |
| } |
| dest += "/${module.name}" |
| source = rebase_path(module.name, "", root_out_dir) |
| }, |
| ] |
| } |
| foreach(driver, pkg.drivers) { |
| pkg_manifest += [ |
| { |
| dest = "driver/${driver.name}" |
| source = rebase_path(driver.name, "", root_out_dir) |
| }, |
| ] |
| } |
| foreach(resource, pkg.resources) { |
| pkg_manifest += [ |
| { |
| dest = "data/${resource.dest}" |
| source = rebase_path(resource.path) |
| }, |
| ] |
| } |
| |
| # TODO(mcgrathr): Remove this when we can! Packages installing |
| # libraries in the system image is all kinds of wrong. |
| foreach(library, pkg.libraries) { |
| pkg_manifest += [ |
| { |
| if (defined(library.dest)) { |
| dest = library.dest |
| } else { |
| dest = library.name |
| } |
| dest = "lib/${dest}" |
| if (defined(library.source)) { |
| source = library.source |
| } else { |
| # TODO(mcgrathr): This breaks when everything is a variant so |
| # that only this here is using the non-variant shlib build. |
| source = get_label_info(shlib_toolchain, "name") |
| source += "/${library.name}" |
| } |
| source = rebase_path(source, "", root_out_dir) |
| }, |
| ] |
| } |
| |
| # Collect all the arguments describing input manifest files |
| # and all the entries we've just synthesized in `pkg_manifest`. |
| manifest_sources = pkg.extra |
| manifest_args = [] |
| foreach(manifest_file, pkg.extra) { |
| manifest_file = rebase_path(manifest_file, root_build_dir) |
| manifest_args += [ "--manifest=${manifest_file}" ] |
| } |
| manifest_args += [ "--entry-manifest=${pkg_label}" ] |
| foreach(entry, pkg_manifest) { |
| manifest_sources += [ entry.source ] |
| manifest_args += [ "--entry=${entry.dest}=${entry.source}" ] |
| } |
| |
| pkg.metadata = { |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| shell_binary_entries = shell_binaries |
| |
| # Subtle: we only want dependency on the package target to consume |
| # package metadata propagation for the package we're building, never |
| # for transitive package dependencies of this package. In the fuchsia |
| # package case, we want to therefore only include our local package |
| # build target. For the system image package case, we don't want to |
| # include anything. |
| package_barrier = [] |
| } |
| |
| if (defined(pkg.visibility)) { |
| pkg.visibility += [ |
| ":$target_name", |
| |
| # TODO(raggi): tighten build/images visibility once we've |
| # finished doing large scale cleanups. |
| "//build/images:*", |
| "//build/packages/*", |
| "//bundles/*", |
| "//garnet/packages/*", |
| "//peridot/packages/*", |
| "//peridot:*", |
| "//src/modular/bundles/*", |
| "//topaz/packages/*", |
| "//vendor/*", |
| ] |
| } |
| |
| # An empty package() target doesn't actually generate a package at all. |
| # Conveniently, an empty system_image package has exactly that effect. |
| if (manifest_sources == [] && pkg.components == []) { |
| pkg.deprecated_system_image = true |
| } |
| |
| if (pkg.deprecated_system_image || bootfs_only) { |
| # System image packages just donate manifest arguments |
| generate_response_file(pkg_target_name) { |
| if (defined(pkg.visibility)) { |
| visibility = pkg.visibility |
| } |
| deps = pkg.deps |
| data_deps = pkg.data_deps |
| public_deps = pkg.public_deps |
| output_name = "${pkg_target_name}.system.rsp" |
| response_file_contents = manifest_args |
| metadata = { |
| forward_variables_from(pkg.metadata, "*") |
| |
| system_image_rsps = [ "@" + |
| rebase_path(target_out_dir + "/" + output_name, |
| root_build_dir) ] |
| } |
| } |
| not_needed([ "component_indices" ]) |
| } else { |
| # Fuchsia package aggregates a manifest from it's arguments and builds a |
| # metadata archive. |
| |
| manifest = "${pkg_target_name}.manifest" |
| |
| # Synthesize the meta/package file. |
| pkg_meta_package = "${pkg_target_name}_meta_package.json" |
| action(pkg_meta_package) { |
| visibility = [ ":$manifest" ] |
| script = "//build/gn/write_package_json.py" |
| outputs = [ |
| "$target_out_dir/$pkg_meta_package", |
| ] |
| args = [ |
| "--name", |
| pkg.package_name, |
| "--version", |
| pkg.package_version, |
| rebase_path(pkg_meta_package, root_build_dir, target_out_dir), |
| ] |
| } |
| |
| generate_manifest(manifest) { |
| visibility = [ ":" + pkg_target_name ] |
| sources = manifest_sources + get_target_outputs(":$pkg_meta_package") |
| args = manifest_args + |
| [ "--entry=meta/package=" + |
| rebase_path(pkg_meta_package, "", target_out_dir) ] |
| deps = pkg.deps + [ ":$pkg_meta_package" ] |
| public_deps = pkg.public_deps |
| |
| foreach(component, pkg.components) { |
| # TODO(CF-162): Add to component_indices |
| deps += [ component ] |
| component_name = get_label_info(component, "name") |
| dir = get_label_info(component, "target_out_dir") |
| rsp_file = "${dir}/${component_name}.rsp" |
| sources += [ rsp_file ] |
| args += [ "@" + rebase_path(rsp_file) ] |
| } |
| } |
| |
| # Next generate a sealed package file. |
| pm_build_package(pkg_target_name) { |
| if (defined(pkg.visibility)) { |
| visibility = pkg.visibility |
| } |
| package_name = pkg.package_name |
| manifest = ":$manifest" |
| metadata = { |
| forward_variables_from(pkg.metadata, "*") |
| |
| component_index = component_indices |
| |
| # We only ever want to collect the following component indices from |
| # packages, not from dependencies of packages, so the barrier prevents |
| # us from walking any further in the dependency chain. See `gn help |
| # walk_keys` for more information on the mechanic. |
| component_index_barrier = [] |
| } |
| |
| deps = pkg.deps |
| data_deps = pkg.data_deps |
| public_deps = pkg.public_deps |
| |
| # Add the dep on the allowlist here rather than in pkg.deps earlier so that we can allow |
| # specific targets by the package target's name using visibility. |
| if (defined(pkg.deprecated_misc_storage)) { |
| deps += [ |
| "${pkg.deprecated_misc_storage}:deprecated_misc_storage_allowlist", |
| ] |
| } |
| if (defined(require_bare_tests_allowlist) && |
| require_bare_tests_allowlist) { |
| deps += [ "//build:deprecated_bare_tests_allowlist" ] |
| } |
| if (defined(pkg.deprecated_shell)) { |
| deps += [ "${pkg.deprecated_shell}:deprecated_shell_allowlist" ] |
| } |
| if (defined(pkg.global_data)) { |
| deps += [ "${pkg.global_data}:global_data_allowlist" ] |
| } |
| if (defined(pkg.rootjob_svc)) { |
| deps += [ "${pkg.rootjob_svc}:rootjob_svc_allowlist" ] |
| } |
| if (defined(pkg.rootresource_svc)) { |
| deps += [ "${pkg.rootresource_svc}:rootresource_svc_allowlist" ] |
| } |
| } |
| } |
| } else { |
| # A reference from a different toolchain, e.g. a variant toolchain, is |
| # just an indirect way to get the package into the system images. |
| # Redirect it as data_deps on the $target_toolchain package. This |
| # really ought to be a pure redirect, i.e. public_deps. But using |
| # data_deps here avoids problems in case some dependency on a package() |
| # target is not in data_deps as it (almost surely) should be. |
| group(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "visibility", |
| "testonly", |
| ]) |
| data_deps = [ |
| ":$target_name($target_toolchain)", |
| ] |
| } |
| |
| # Suppress unused variable warnings. |
| not_needed(invoker, "*") |
| } |
| } |