| # 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/config/clang/clang.gni") |
| |
| declare_args() { |
| # Build packages as FAR archives and store them in /system. This is required |
| # for --bootfs builds. |
| bootfs_packages = false |
| } |
| |
| # 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 |
| # |
| # fuchsia_package (bool, optional) |
| # If true, the package is constructed and signed ready for distribution and |
| # inclusion in /pkgfs. system_image supersedes fuchsia_package. |
| # |
| # TODO(PKG-46) Eventually all packages should be fuchsia_package.. |
| # |
| # Defaults to false. |
| # |
| # system_image (bool, optional) |
| # If true, the package is stored in the system boot image rather than in a |
| # Fuchsia Archive. |
| # |
| # If this package uses the |drivers| parameter, the system_image must be set |
| # to true because we are not yet sophisticated enough to load drivers out of |
| # archives. |
| # |
| # Defaults to false. |
| # |
| # deprecated_system_image (bool, optional) |
| # New alias for system_image to reflect its deprecated status, per PKG-46. |
| # |
| # boot_firmware_image (bool, optional) |
| # If true, the package is a boot firmware package instead of a regular |
| # package. A boot firmware package may contain only resources which are |
| # installed into /boot/lib/fw. |
| # |
| # meta (optional) |
| # List of scopes defining 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 |system_image| to be false. |
| # |
| # Entries in a scope in the meta list: |
| # |
| # path (path, required) |
| # 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() rule. If the resource is |
| # generated, this will typically be specified relative to |
| # $target_gen_dir |
| # |
| # dest (path, required) |
| # Location the resource will be placed within "meta/" |
| # |
| # binary (optional) |
| # The path to the the primary binary for the package, relative to |
| # $root_build_dir. The binary will be placed in the assembled package at |
| # "bin/app" and will be executed by default when running the package. |
| # |
| # Requires |system_image| to be false. |
| # |
| # binaries (optional) |
| # List of scopes defining 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 (string, required) |
| # Name of the binary |
| # |
| # source (path, optional) |
| # Location of the binary in the build directory if it is not at |
| # $root_build_dir/$name |
| # |
| # dest (path, optional) |
| # Location the binary will be placed within "bin/" |
| # |
| # tests (optional) |
| # List of scopes defining 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 (string, required) |
| # Name of the test |
| # |
| # dest (path, optional) |
| # Location the binary will be placed within "test/" |
| # |
| # disabled (bool, optional) |
| # 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. |
| # |
| # drivers (optional) |
| # List of scopes defining 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 |system_image| to be true. |
| # |
| # Entries in a scope in the drivers list: |
| # |
| # name (string, required) |
| # Name of the driver |
| # |
| # libraries (optional) |
| # List of scopes defining the (shared) libraries in the package. A library |
| # is placed in the "lib/" directory of the assembled package. |
| # |
| # Entries in a scope in the libraries list: |
| # |
| # name (string, required) |
| # Name of the library |
| # |
| # source (path, optional) |
| # Location of the binary in the build directory if it is not at |
| # $root_build_dir/$name |
| # |
| # dest (path, optional) |
| # Location the binary will be placed within "lib/" |
| # |
| # resources (optional) |
| # List of scopes defining 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 (path, required) |
| # 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() rule. If the resource is |
| # generated, this will typically be specified relative to |
| # $target_gen_dir |
| # |
| # dest (path, required) |
| # Location the resource will be placed within "data/", unless the package |
| # is a boot firmware package in which case this is the location the resource |
| # will be placed within "/boot/lib/fw". |
| # |
| # extra (optional) |
| # A list of potentially build-time generated files containing extra entries |
| # in the package, formatted as a manifest. |
| template("package") { |
| if (current_toolchain == target_toolchain) { |
| pkg = { |
| # By default we want to build Fuchsia packages, but they are not |
| # supported under bootfs, so in that case we build the old archive format |
| # packages. |
| fuchsia_package = !bootfs_packages |
| system_image = false |
| deprecated_system_image = false |
| boot_firmware_image = false |
| binaries = [] |
| drivers = [] |
| libraries = [] |
| meta = [] |
| package_name = target_name |
| package_version = "0" # placeholder |
| resources = [] |
| tests = [] |
| forward_variables_from(invoker, "*") |
| } |
| pkg_out_dir = "$root_build_dir/package/${pkg.package_name}" |
| |
| if (pkg.deprecated_system_image) { |
| pkg.system_image = true |
| } |
| |
| shared_toolchain_out_dir = |
| get_label_info("//lib($shlib_toolchain)", "root_out_dir") |
| not_needed([ "shared_toolchain_out_dir" ]) |
| |
| assert(pkg.drivers == [] || pkg.system_image) |
| |
| if (pkg.boot_firmware_image) { |
| assert(!pkg.fuchsia_package, |
| "boot firmware packages cannot be true fuchsia packages") |
| assert(!pkg.system_image, |
| "boot firmware packages cannot be system images") |
| assert(pkg.binaries == [], |
| "boot firmware packages cannot contain binaries") |
| assert(pkg.drivers == [], "boot firmware packages cannot contain drivers") |
| assert(pkg.libraries == [], |
| "boot firmware packages cannot contain libraries") |
| assert(pkg.meta == [], "boot firmware packages cannot contain metadata") |
| assert(pkg.tests == [], "boot firmware packages cannot contain tests") |
| assert(!defined(pkg.extra) || pkg.extra == [], |
| "boot firmware packages cannot contain extra build-time entries") |
| } |
| |
| package_manifest = "$pkg_out_dir/package_manifest" |
| archive_manifest = "$pkg_out_dir/archive_manifest" |
| system_manifest = "$pkg_out_dir/system_manifest" |
| boot_manifest = "$pkg_out_dir/boot_manifest" |
| |
| manifest_target_name = "${target_name}__manifest" |
| |
| # If there are extra build-time entries to put into the package, then |
| # collect GN-time entries in partial_package_manifest, and concatenate them |
| # with the build-time entries into package_manifest. |
| if (defined(pkg.extra)) { |
| extra_target_name = "${target_name}__extra" |
| if (pkg.fuchsia_package) { |
| partial_archive_manifest = archive_manifest |
| partial_package_manifest = "$pkg_out_dir/partial_package_manifest" |
| partial = partial_package_manifest |
| output = package_manifest |
| } else { |
| partial_archive_manifest = "$pkg_out_dir/partial_archive_manifest" |
| partial_package_manifest = package_manifest |
| partial = partial_archive_manifest |
| output = archive_manifest |
| } |
| action(extra_target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| deps = [ ":${manifest_target_name}" ] + invoker.deps |
| inputs = [ partial ] + pkg.extra |
| outputs = [ |
| output, |
| ] |
| script = "//build/gn/combine_manifests.py" |
| args = [ |
| rebase_path(output, root_build_dir), |
| rebase_path(partial, root_build_dir), |
| ] |
| foreach(extra, pkg.extra) { |
| args += [ rebase_path(extra, root_build_dir) ] |
| } |
| } |
| } else { |
| partial_package_manifest = package_manifest |
| partial_archive_manifest = archive_manifest |
| } |
| |
| contents = [] |
| extra_inputs = [] |
| |
| foreach(entry, pkg.meta) { |
| assert(!pkg.system_image, "Metadata cannot be used in system packages.") |
| source = entry.path |
| dest = "meta/${entry.dest}" |
| contents += [ "$dest=$source" ] |
| extra_inputs += [ source ] |
| } |
| if (defined(pkg.binary)) { |
| assert( |
| !pkg.system_image, |
| "Binary requires the package to be archived. Consider using 'binaries' for system packages.") |
| source = rebase_path("$root_build_dir/${pkg.binary}") |
| contents += [ "bin/app=$source" ] |
| extra_inputs += [ source ] |
| } |
| foreach(binary, pkg.binaries) { |
| assert( |
| (pkg.system_image || pkg.fuchsia_package), |
| "Binaries cannot be used in archived packages. Consider using 'binary'.") |
| |
| # Binary paths are relative to the root of the build dir. |
| if (defined(binary.source)) { |
| source = rebase_path("$root_build_dir/${binary.source}") |
| } else { |
| source = rebase_path("$root_build_dir/${binary.name}") |
| } |
| dirname = "bin" |
| basename = binary.name |
| if (defined(binary.dest)) { |
| basename = binary.dest |
| } |
| contents += [ "$dirname/$basename=$source" ] |
| extra_inputs += [ source ] |
| } |
| foreach(test, pkg.tests) { |
| source = rebase_path("$root_build_dir/${test.name}") |
| basename = test.name |
| if (defined(test.dest)) { |
| basename = test.dest |
| } |
| if (defined(test.disabled) && test.disabled) { |
| dest = "test/disabled/" + basename |
| } else { |
| dest = "test/" + basename |
| } |
| contents += [ "$dest=$source" ] |
| extra_inputs += [ source ] |
| } |
| foreach(driver, pkg.drivers) { |
| # Driver paths are relative to the root of the build dir. |
| source = rebase_path("$root_build_dir/${driver.name}") |
| dest = "driver/" + driver.name |
| |
| contents += [ "$dest=$source" ] |
| extra_inputs += [ source ] |
| } |
| foreach(library, pkg.libraries) { |
| # Library paths are relative to the root of the build dir. |
| if (defined(library.source)) { |
| library_path = rebase_path(library.source) |
| } else { |
| library_path = "$shared_toolchain_out_dir/${library.name}" |
| } |
| source = rebase_path(library_path) |
| if (defined(library.dest)) { |
| dest = "lib/" + library.dest |
| } else { |
| dest = "lib/" + library.name |
| } |
| contents += [ "$dest=$source" ] |
| extra_inputs += [ source ] |
| } |
| foreach(resource, pkg.resources) { |
| # Resource path are absolute. |
| source = resource.path |
| if (pkg.boot_firmware_image) { |
| dest = "lib/fw/" + resource.dest |
| } else { |
| dest = "data/" + resource.dest |
| } |
| contents += [ "$dest=$source" ] |
| extra_inputs += [ source ] |
| } |
| |
| if (pkg.system_image || pkg.boot_firmware_image) { |
| action(manifest_target_name) { |
| script = "//build/gn/write_manifest.py" |
| outputs = [ |
| partial_package_manifest, |
| partial_archive_manifest, |
| system_manifest, |
| boot_manifest, |
| ] |
| args = [ |
| "--manifest", |
| rebase_path(partial_package_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(partial_archive_manifest, root_build_dir), |
| ] |
| if (pkg.boot_firmware_image) { |
| args += [ |
| "--manifest", |
| rebase_path(system_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(boot_manifest, root_build_dir), |
| ] |
| } else { |
| args += [ |
| "--manifest", |
| rebase_path(boot_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(system_manifest, root_build_dir), |
| ] |
| } |
| |
| args += contents |
| inputs = extra_inputs |
| |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "testonly", |
| ]) |
| } |
| |
| group(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| public_deps = [ |
| ":${manifest_target_name}", |
| ] |
| if (defined(pkg.extra)) { |
| public_deps += [ ":${extra_target_name}" ] |
| } |
| } |
| } else if (pkg.fuchsia_package) { |
| # If the caller doesn't supply a package, we'll generate one |
| need_package_json = true |
| foreach(meta, pkg.meta) { |
| if (meta == "package") { |
| need_package_json = false |
| } |
| } |
| |
| if (need_package_json) { |
| package_json_file = "$pkg_out_dir/meta/package" |
| package_json_target_name = "${target_name}_package_json" |
| |
| action(package_json_target_name) { |
| script = "//build/gn/write_package_json.py" |
| outputs = [ |
| package_json_file, |
| ] |
| args = [ |
| "--name", |
| pkg.package_name, |
| "--version", |
| pkg.package_version, |
| rebase_path(package_json_file, root_build_dir), |
| ] |
| } |
| |
| full_pkg_json_file = rebase_path(package_json_file) |
| contents += [ "meta/package=${full_pkg_json_file}" ] |
| extra_inputs += [ package_json_file ] |
| } |
| |
| action(manifest_target_name) { |
| script = "//build/gn/write_manifest.py" |
| outputs = [ |
| partial_package_manifest, |
| partial_archive_manifest, |
| system_manifest, |
| boot_manifest, |
| ] |
| args = [ |
| "--manifest", |
| rebase_path(partial_archive_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(system_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(boot_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(partial_package_manifest, root_build_dir), |
| ] + contents |
| inputs = extra_inputs |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "testonly", |
| ]) |
| if (!defined(deps)) { |
| deps = [] |
| } |
| if (need_package_json) { |
| deps += [ ":${package_json_target_name}" ] |
| } |
| } |
| |
| group(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| public_deps = [ |
| ":${manifest_target_name}", |
| ] |
| if (defined(pkg.extra)) { |
| public_deps += [ ":${extra_target_name}" ] |
| } |
| } |
| } else { |
| output = "$pkg_out_dir/${pkg.package_name}.far" |
| |
| action(manifest_target_name) { |
| script = "//build/gn/write_manifest.py" |
| outputs = [ |
| partial_package_manifest, |
| partial_archive_manifest, |
| system_manifest, |
| boot_manifest, |
| ] |
| args = [ |
| "--manifest", |
| rebase_path(partial_package_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(system_manifest, root_build_dir), |
| "pkgs/${pkg.package_name}=" + rebase_path(output), |
| "--manifest", |
| rebase_path(boot_manifest, root_build_dir), |
| "--manifest", |
| rebase_path(partial_archive_manifest, root_build_dir), |
| ] + contents |
| inputs = extra_inputs |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "testonly", |
| ]) |
| } |
| |
| # This action assembles an image containing all binaries, tests, drivers, |
| # libraries, and resources defined in the package. |
| action(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| public_deps = [ |
| ":${manifest_target_name}", |
| ] |
| if (defined(pkg.extra)) { |
| public_deps += [ ":${extra_target_name}" ] |
| } |
| |
| archiver_label = "//garnet/bin/far:bin($host_toolchain)" |
| deps = [ |
| archiver_label, |
| ] |
| |
| archiver_out_dir = get_label_info(archiver_label, "root_out_dir") |
| far_path = "$archiver_out_dir/far" |
| |
| script = "//build/gn_run_binary.sh" |
| inputs = [ |
| far_path, |
| archive_manifest, |
| ] |
| outputs = [ |
| output, |
| ] |
| args = [ |
| clang_prefix, |
| rebase_path(far_path, root_build_dir), |
| "create", |
| "--archive=" + rebase_path(output), |
| "--manifest=" + rebase_path(archive_manifest), |
| ] |
| } |
| } |
| } else { |
| group(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "deps", |
| ]) |
| } |
| |
| # Suppress unused variable warnings. |
| not_needed(invoker, "*") |
| } |
| } |