blob: 3f02149b189125610256064cd334cef4a7d56260 [file] [log] [blame]
# Copyright 2023 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/cpp/library_headers.gni")
# Compile a binary blob into an RODATA object that can be linked into code.
#
# This produces a source_set() target that compiles generated assembly code to
# define a pair of symbols around an RODATA object containing the contents of a
# raw binary input file. C++ code with this target in $deps can access the blob
# by using `#include "${output_name}_blob.h"` to provide a constexpr function
# `${output_name}_blob()` that returns cpp20::span<const std::byte>.
#
# Note that the RODATA object will have no special alignment guarantees but
# instead must be copied at runtime to someplace that is aligned appropriately
# for how the data will be used.
#
# Parameters
#
# * sources
# - Required: Must be a list of exactly one file. This is the file that
# will be embedded as an RODATA object.
# - Type: list(file)
#
# * deps, public_deps
# - Optional: Should include anything that generates $sources.
# Use $public_deps to propagate public_configs and public_deps.
# - Type: list(label)
# - Default: []
#
# * output_name
# - Optional: This is used to choose the symbol names in the generated
# linkable object. The names will be "embedded_blob.start.$output_name"
# and "embedded_blob.end.$output_name" for symbols that point to the
# start and end of the object respectively. These symbols are used by
# the "${output_name}_blob()" C++ constexpr function, which is defined
# in a generated header file called "${output_name}_blob.h".
# - Type: string
# - Default: target_name
#
# * visibility, testonly
# - Optional: As for source_set().
#
template("embedded_blob") {
label = get_label_info(":$target_name", "label_with_toolchain")
assert(defined(invoker.sources),
"sources is required for embedded_blob() $label")
if (defined(invoker.output_name)) {
output_name = invoker.output_name
} else {
output_name = target_name
}
blobs = invoker.sources
assert(blobs != [] && blobs == [ blobs[0] ],
"sources must have exactly one element for embedded_blob() $label")
blob = blobs[0]
blob_path = rebase_path(blob, root_build_dir)
start_label = "embedded_blob.start.$output_name"
end_label = "embedded_blob.end.$output_name"
main_target = target_name
gen_asm_target = "_embedded_blob.$target_name.gen_asm"
gen_header_target = "_embedded_blob.$target_name.gen_header"
headers_target = "_embedded_blob.$target_name.headers"
gen_asm_file = "$target_gen_dir/embedded_blob.$output_name.S"
gen_header_file = "$target_gen_dir/include/${output_name}_blob.h"
generated_file(gen_asm_target) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":*" ]
outputs = [ gen_asm_file ]
output_conversion = "list lines"
contents = [
"// Generated by $label. DO NOT EDIT!",
".section .rodata, \"a\", %progbits",
".globl $start_label",
"$start_label:",
".incbin \"$blob_path\"",
".size $start_label, . - $start_label",
".globl $end_label",
"$end_label:",
]
}
generated_file(gen_header_target) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":*" ]
outputs = [ gen_header_file ]
output_conversion = "list lines"
contents = [
"// Generated by $label. DO NOT EDIT!",
"#pragma once",
"#include <lib/stdcompat/span.h>",
"constexpr cpp20::span<const std::byte> ${output_name}_blob() {",
" extern const std::byte start[] __asm__(\"$start_label\");",
" extern const std::byte end[] __asm__(\"$end_label\");",
" return {+start, +end};",
"}",
]
}
library_headers(headers_target) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":*" ]
include_dir = get_path_info(gen_header_file, "dir")
headers = [ get_path_info(gen_header_file, "file") ]
deps = [ ":$gen_header_target" ]
public_deps = [ "//sdk/lib/stdcompat" ]
}
source_set(main_target) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"visibility",
"testonly",
])
if (!defined(deps)) {
deps = []
}
if (!defined(public_deps)) {
public_deps = []
}
public_deps += [ ":$headers_target" ]
deps += [ ":$gen_asm_target" ]
sources = [ gen_asm_file ]
inputs = [ blob ]
}
}