blob: 615c90b174901a13d00d44d1cf9ca1d52e2aeb68 [file] [log] [blame]
# 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.
declare_args() {
# Path to the root of the zircon build directory.
zircon_build_dir = "//out//build-zircon"
}
# 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
#
# app (bool, optional)
# If true, changes the default location of binaries from
# |"bin/" + binary.name| to |"apps/" + binary.name|.
#
# archive (bool, optional)
# If true, the package is stored in a Fuchsia Archive rather than directly
# in the system boot image.
#
# Cannot be used with the drivers parameter because the system is not yet
# sophisticated enough to load drivers out of archives.
#
# 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 |archive| to be true.
#
# 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/"
#
# 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.
#
# Entries in a scope in the drivers list:
#
# name (string, required)
# Name of the driver
#
# early_boot_driver (bool, optional)
# Set if this driver must be available at early boot time. Most drivers
# should not set this.
#
# 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/"
#
# used_by_early_boot_drivers (bool, optional)
# Set to true if this library is used by a boot driver. This will place
# the library in a location accessible to drivers during early boot as
# well as other programs.
#
# 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/"
#
template("package") {
if (current_toolchain == target_toolchain) {
pkg = {
app = false
archive = false
binaries = []
drivers = []
libraries = []
meta = []
package_name = target_name
resources = []
tests = []
forward_variables_from(invoker, "*")
}
pkg_out_dir = "$root_build_dir/package/${pkg.package_name}"
shared_toolchain_out_dir = get_label_info("//lib($shlib_toolchain)",
"root_out_dir")
not_needed(["shared_toolchain_out_dir"])
assert(pkg.drivers == [] || !pkg.archive)
mkfs_target = target_name + "_mkfs"
extract_buildids_target = target_name + "_extract_buildids"
# This action assembles an image containing all binaries, tests, drivers,
# libraries, and resources defined in the package.
action(mkfs_target) {
forward_variables_from(invoker,
[
"deps",
"testonly",
])
package_manifest_contents = []
boot_manifest_contents = []
sources = []
foreach(entry, pkg.meta) {
assert(pkg.archive, "Metadata requires the package to be archived.")
source = entry.path
sources += [ entry.path ]
dest = "meta/${entry.dest}"
package_manifest_contents += [ "$dest=$source" ]
}
foreach(binary, pkg.binaries) {
# Binary paths are relative to the root of the build dir.
if (defined(binary.source)) {
source = rebase_path("$root_build_dir/${binary.source}")
sources += [ "$root_build_dir/${binary.source}" ]
} else {
source = rebase_path("$root_build_dir/${binary.name}")
sources += [ "$root_build_dir/${binary.name}" ]
}
dirname = "bin"
if (pkg.app) {
dirname = "apps"
}
basename = binary.name
if (defined(binary.dest)) {
basename = binary.dest
}
package_manifest_contents += [ "$dirname/$basename=$source" ]
}
foreach(test, pkg.tests) {
source = rebase_path("$root_build_dir/${test.name}")
sources += [ "$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
}
package_manifest_contents += [ "$dest=$source" ]
}
foreach(driver, pkg.drivers) {
# Driver paths are relative to the root of the build dir.
source = rebase_path("$root_build_dir/${driver.name}")
sources += [ "$root_build_dir/${driver.name}" ]
dest = "driver/" + driver.name
if (defined(driver.early_boot_driver) && driver.early_boot_driver) {
# Early boot drivers go in the boot manifest.
# TODO(jamesr): Once devmgr can reliably load all drivers off of /system,
# unwind this.
boot_manifest_contents += [ "$dest=$source" ]
} else {
package_manifest_contents += [ "$dest=$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)
sources += [ library_path ]
if (defined(library.dest)) {
dest = "lib/" + library.dest
} else {
dest = "lib/" + library.name
}
if (defined(library.used_by_early_boot_drivers) &&
library.used_by_early_boot_drivers) {
boot_manifest_contents += [ "$dest=$source" ]
} else {
package_manifest_contents += [ "$dest=$source" ]
}
}
foreach(resource, pkg.resources) {
# Resource path are absolute.
source = resource.path
sources += [ resource.path ]
dest = "data/" + resource.dest
package_manifest_contents += [ "$dest=$source" ]
}
boot_manifest = "$pkg_out_dir/boot_manifest"
write_file(boot_manifest, boot_manifest_contents)
system_manifest = "$pkg_out_dir/system_manifest"
archive_manifest = "$pkg_out_dir/archive_manifest"
if (pkg.archive) {
assert(boot_manifest_contents == [])
assert(package_manifest_contents != [])
write_file(archive_manifest, package_manifest_contents)
archiver_label = "//garnet/bin/far($host_toolchain)"
deps += [ archiver_label ]
archiver_out_dir = get_label_info(archiver_label, "root_out_dir")
far_path = "$archiver_out_dir/far"
output = "$pkg_out_dir/${pkg.package_name}.far"
script = far_path
outputs = [
output,
]
args = [
"create",
"--archive=" + rebase_path(output),
"--manifest=" + rebase_path(archive_manifest),
]
write_file(system_manifest,
[ "pkgs/${pkg.package_name}=" + rebase_path(output) ])
} else {
write_file(system_manifest, package_manifest_contents)
write_file(archive_manifest, [])
# We have to do something in our action
script = "/usr/bin/touch"
output = "$pkg_out_dir/.stamp"
outputs = [
output,
]
args = [ rebase_path(output) ]
}
}
# This action extracts build ids from all binaries and libraries in the
# package and writes them into a ids.txt file in a predictable location.
action(extract_buildids_target) {
forward_variables_from(invoker,
[
"deps",
"testonly",
])
id_file = "$pkg_out_dir/ids.txt"
script = "//packages/gn/read_build_ids.py"
outputs = [
id_file,
]
args = [ rebase_path(id_file) ]
foreach(binary, pkg.binaries) {
args += [ rebase_path("$root_build_dir/${binary.name}") ]
}
foreach(test, pkg.tests) {
args += [ rebase_path("$root_build_dir/${test.name}") ]
}
foreach(driver, pkg.drivers) {
driver_path = rebase_path("$root_build_dir/${driver.name}")
args += [ rebase_path(driver_path) ]
}
foreach(library, pkg.libraries) {
library_path = "$shared_toolchain_out_dir/${library.name}"
args += [ rebase_path(library_path) ]
}
}
group(target_name) {
forward_variables_from(invoker, [ "testonly" ])
deps = [
":" + mkfs_target,
":" + extract_buildids_target,
]
}
} else {
group(target_name) {
forward_variables_from(invoker,
[
"testonly",
"deps",
])
}
# Suppress unused variable warnings.
not_needed(invoker, "*")
}
}