blob: 8c574fbeca55d36c174336a70b13333e6f2c7b33 [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.
import("//build/toolchain/shared.gni")
declare_args() {
# Path to the root of the magenta build directory.
magenta_build_dir = "//out//build-magenta"
}
# 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:
#
# source (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
#
# 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.
#
# Temporarily, drivers are mapped to the "/boot" bootfs instead of the
# "/system" bootfs most other package components are mapped into, pending
# improvements to the device manager. For this reason, the drivers parameter
# is mutually exclusive with the archive boolean.
#
# 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
#
# 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:
#
# source (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) {
binaries = []
drivers = []
libraries = []
meta = []
resources = []
tests = []
package_name = target_name
if (defined(invoker.package_name)) {
package_name = invoker.package_name
}
if (defined(invoker.meta)) {
meta = invoker.meta
}
if (defined(invoker.binaries)) {
binaries = invoker.binaries
}
if (defined(invoker.tests)) {
tests = invoker.tests
}
if (defined(invoker.drivers)) {
drivers = invoker.drivers
}
if (defined(invoker.libraries)) {
libraries = invoker.libraries
}
if (defined(invoker.resources)) {
resources = invoker.resources
}
output_base = "$root_build_dir/package/$package_name/"
assert(!defined(invoker.drivers) || !defined(invoker.archive) ||
!invoker.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, meta) {
assert(defined(invoker.archive) && invoker.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, binaries) {
if (defined(binary.source)) {
source = rebase_path(binary.source)
sources += [ root_build_dir + "/" + binary.source ]
} else {
# Default binary paths are relative to the root of the build dir.
source = rebase_path(root_build_dir + "/" + binary.name)
sources += [ root_build_dir + "/" + binary.name ]
}
if (defined(binary.dest)) {
dest = "bin/" + binary.dest
} else {
if (defined(invoker.app) && invoker.app) {
dest = "apps/" + binary.name
} else {
dest = "bin/" + binary.name
}
}
package_manifest_contents += [ "$dest=$source" ]
}
foreach(test, tests) {
source = rebase_path(root_build_dir + "/" + test.name)
sources += [ root_build_dir + "/" + test.name ]
dest = "test/" + test.name
package_manifest_contents += [ "$dest=$source" ]
}
foreach(driver, drivers) {
# Driver paths are relative to the root of the build dir.
source = rebase_path(root_build_dir + "/${shared_toolchain_out_dir}/" + driver.name)
sources += [ root_build_dir + "/${shared_toolchain_out_dir}/" + driver.name ]
dest = "driver/" + driver.name
# Drivers go in the boot manifest.
# TODO(jamesr): Once devmgr can reliably load drivers off of /system,
# unwind this.
boot_manifest_contents += [ "$dest=$source" ]
}
foreach(library, libraries) {
# Library paths are relative to the root of the build dir.
library_path = root_build_dir + "/${shared_toolchain_out_dir}/" + library.name
source = rebase_path(library_path)
sources += [ library_path ]
dest = "lib/" + library.name
package_manifest_contents += [ "$dest=$source" ]
}
foreach(resource, resources) {
# Resource path are absolute.
source = resource.path
sources += [ resource.path ]
dest = "data/" + resource.dest
package_manifest_contents += [ "$dest=$source" ]
}
boot_manifest = output_base + "boot_manifest"
write_file(boot_manifest, boot_manifest_contents)
system_manifest = output_base + "system_manifest"
archive_manifest = output_base + "archive_manifest"
if (defined(invoker.archive) && invoker.archive) {
assert(boot_manifest_contents == [])
assert(package_manifest_contents != [])
write_file(archive_manifest, package_manifest_contents)
deps += [ "//application/src/archiver($host_toolchain)" ]
far_path = "$root_build_dir/host_$host_cpu/far"
output = output_base + package_name + ".far"
script = far_path
outputs = [
output,
]
args = [
"create",
"--archive=" + rebase_path(output),
"--manifest=" + rebase_path(archive_manifest),
]
write_file(system_manifest,
[ "pkgs/$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 = output_base + ".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 = output_base + "ids.txt"
script = "//packages/gn/read_build_ids.py"
outputs = [
id_file,
]
args = [ rebase_path(id_file) ]
foreach(binary, binaries) {
args += [ rebase_path(root_build_dir + "/" + binary.name) ]
}
foreach(test, tests) {
args += [ rebase_path(root_build_dir + "/" + test.name) ]
}
foreach(driver, drivers) {
args += [ rebase_path(root_build_dir + "/" + driver.name) ]
}
foreach(library, libraries) {
args += [ rebase_path(root_build_dir + "/" + library.name) ]
}
}
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
assert(!defined(invoker.app) || invoker.app != "")
assert(!defined(invoker.archive) || invoker.archive != "")
assert(!defined(invoker.binaries) || invoker.binaries != [])
assert(!defined(invoker.drivers) || invoker.drivers != [])
assert(!defined(invoker.libraries) || invoker.libraries != [])
assert(!defined(invoker.meta) || invoker.meta != [])
assert(!defined(invoker.package_name) || invoker.package_name != "")
assert(!defined(invoker.resources) || invoker.resources != [])
assert(!defined(invoker.tests) || invoker.tests != [])
}
}