| # 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 ] |
| } |
| } |