blob: 65ebb5193a65c9b3bec3055b395ca74f53f7bf59 [file] [log] [blame]
# Copyright 2019 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")
# Like action() but using utility binaries from the C/C++ toolchain.
# This is the way to use `nm`, `objcopy`, etc.
#
# Parameters
#
# utils
# Required: Utilities to use, e.g. "nm", "objcopy", "objdump".
# Type: list(string)
#
# script
# Optional: Same as for action(). The script receives an implicit
# argument for each element in $utils giving the command to run.
# If omitted, then $utils must have only one element and that command
# itself will be run with $args just as given. This can be true instead
# of a string for automatic response file handling; see notes below.
# Type: file or true (see below)
#
# args
# Required: Same as for action(). If there is a $script,
# the implicit $utils arguments precede $args.
# Type: list(string)
#
# depfile, deps, inputs, outputs, sources, testonly, visibility
# See action().
#
# Notes on response files
#
# When using "@rspfile" command-line syntax, its crucial that any input
# files fed to $utils are recorded as dependencies. GN won't be aware of
# this file dependency because it only knows about the response *file*, not
# the response file's *contents*. This target will depend on the target
# that generates the response file (e.g. a link_output_rspfile() target)
# and that gives this target a transitive order-only dependency to ensure
# the input exists. To make Ninja aware of the dependency to ensure that
# incremental rebuilds re-run this action when needed, use $depfile.
#
# When running $utils directly, set $script to true (and do not set
# $depfile) to use a standard script that handles dependencies for the
# simple "@RSPFILE" cases. In this mode, each $args string that looks like
# "@RSPFILE" will cause implicit dependencies (after the fact, via depfile)
# on each file listed in "RSPFILE" (one file per line with no quoting).
# Most toolchain utilities have built-in "@RSPFILE" support, but the script
# also does remedial "@RSPFILE" expansion for utilities known to lack it.
#
template("toolchain_utils_action") {
assert(defined(invoker.utils),
"toolchain_utils_action(\"$target_name\") requires `utils`")
utils_inputs = []
utils_paths = []
# The GN build only supports prebuilt Clang at the moment.
foreach(util, invoker.utils) {
if (util == "cc") {
util = "clang"
} else {
util = "llvm-${util}"
}
util_path = "${clang_prefix}/${util}"
utils_inputs += [ util_path ]
utils_paths += [ rebase_path(util_path, root_build_dir) ]
}
action(target_name) {
forward_variables_from(invoker,
"*",
[
"args",
"target",
"utils",
])
if (!defined(inputs)) {
inputs = []
}
inputs += utils_inputs
if (defined(script)) {
if (script == true) {
assert(!defined(depfile),
"script=true is incompatible with setting depfile")
script = "//build/zircon/toolchain_utils_action.sh"
depfile = "$target_out_dir/_host_tool_action.$target_name.d"
args = [
rebase_path(outputs[0], root_build_dir),
rebase_path(depfile, root_build_dir),
]
} else {
script = script
args = []
}
args += utils_paths + invoker.args
} else {
script = rebase_path(utils_paths[0], "", root_build_dir)
assert(
utils_paths == [ utils_paths[0] ],
"toolchain_utils_action(\"$target_name\") without `script` must have exactly one element in `utils`")
args = invoker.args
}
}
}
# generated_file() containing output file name of a linking target.
#
# Parameters
#
# deps, outputs, testonly, visibility
# See generated_file(). $deps determines the contents as described below.
#
# This produces a generated_file() target with $outputs as given. The
# contents of the file list the link outputs reached by $deps. That is,
# for each target that links a binary (executable(), loadable_module(),
# shared_library() via library(), etc.) the path relative to
# $root_build_dir of the actual binary created by the linker (before
# stripping) will be listed, one per line. The dependency traversal is
# pruned at each linking target, so e.g. if an executable() is listed then
# neither its shared_library() dependencies nor any $data_deps leading to
# loadable_module() or executable() targets will be listed.
#
template("link_output_rspfile") {
generated_file(target_name) {
forward_variables_from(invoker,
[
"deps",
"outputs",
"testonly",
"visibility",
])
# Every terminal target provides these metadata keys. The first is
# used as the data key for the output of the link, as a file name
# relative to $root_build_dir appropriate for command-line contexts.
# The second is used as a walk key to provide a dependency barrier
# against e.g. shared_library() deps or other executable() data_deps.
#
# Used in: //build/config/BUILDCONFIG.gn
data_keys = [ "link_output_path" ]
walk_keys = [ "link_output_barrier" ]
output_conversion = "list lines"
}
}
# Define an action to convert an ELF file to a raw binary image file.
#
# Parameters
#
# deps
# Required: Dependencies leading to a linking target (e.g. executable).
# The ${metadata.link_output_path} key is used to find the input ELF file.
# Type: list(label)
#
# output_name
# Optional: Basename of the output file.
# Type: string
# Default: $target_name
#
# output_dir
# Optional: Directory for the output file.
# Type: dir
# Default: $target_out_dir
#
# output_extension
# Optional: Extension added to $output_name (after a `.` if nonempty).
# Type: string
# Default: "bin"
#
# pure
# Optional: Check that executable needs no runtime relocation.
# This assumes it was linked with `--emit-relocs`.
# Type: bool
# Default: false
#
template("image_binary") {
image_target = target_name
rspfile_target = "_image_binary.rsp.$target_name"
rspfile = "$target_gen_dir/$target_name.image.rsp"
check_target = "_image_binary.pure-check.$target_name"
image_target_visibility = [ ":$image_target" ]
link_output_rspfile(rspfile_target) {
forward_variables_from(invoker,
[
"deps",
"testonly",
])
visibility = image_target_visibility + [ ":$check_target" ]
outputs = [ rspfile ]
}
image_deps = [ ":$rspfile_target" ]
if (defined(invoker.pure) && invoker.pure) {
image_deps += [ ":$check_target" ]
toolchain_utils_action(check_target) {
visibility = image_target_visibility
forward_variables_from(invoker, [ "testonly" ])
deps = [ ":$rspfile_target" ]
sources = [ rspfile ]
outputs = [ "$target_out_dir/$image_target.pure-stamp" ]
script = "//zircon/kernel/gen-kaslr-fixups.sh"
utils = [
"readelf",
"objdump",
]
depfile = "$target_out_dir/_image_binary.$target_name.d"
args = [
"--pure",
"@" + rebase_path(rspfile, root_build_dir),
rebase_path(outputs[0], root_build_dir),
rebase_path(depfile, root_build_dir),
]
}
}
toolchain_utils_action(image_target) {
deps = image_deps
forward_variables_from(invoker,
[
"metadata",
"output_dir",
"output_extension",
"output_name",
"testonly",
"visibility",
])
if (!defined(output_dir)) {
output_dir = target_out_dir
}
if (!defined(output_extension)) {
output_extension = "bin"
}
if (!defined(output_name)) {
output_name = target_name
}
output_file = "$output_dir/$output_name"
if (output_extension != "") {
output_file += ".$output_extension"
}
utils = [ "objcopy" ]
script = true
sources = [ rspfile ]
outputs = [ output_file ]
args = [
"-O",
"binary",
"@" + rebase_path(rspfile, root_build_dir),
rebase_path(output_file, root_build_dir),
]
}
}