Skip to content

Commit

Permalink
pw_build: Updates to pw_cc_blob_library
Browse files Browse the repository at this point in the history
- Support specifying the alignment of the blob with the alignas
  argument.
- Require the namespace argument.
- Isolate blob include paths under "$target_gen_dir/$target_name" so
  they aren't shared by all blobs declared in the same directory.
- No longer use different one-line formatting for short blobs to
  simplify code generation.
- Add a unit test that checks the contents of a blob.

Change-Id: I61d58b6cb95576a89fd8123b9f41ffeb0db38860
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/100801
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
  • Loading branch information
255 authored and CQ Bot Account committed Jul 8, 2022
1 parent 7b703f7 commit 867ddb8
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 195 deletions.
7 changes: 7 additions & 0 deletions pw_build/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,10 @@ config_setting(
"define": "kythe_corpus=pigweed.googlesource.com/pigweed/pigweed",
},
)

# TODO(b/238339027): Run cc_blob_library_test when pw_cc_blob_library is
# supported in Bazel.
filegroup(
name = "cc_blob_library_test",
srcs = ["cc_blob_library_test.cc"],
)
28 changes: 28 additions & 0 deletions pw_build/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@

import("//build_overrides/pigweed.gni")

import("$dir_pw_build/cc_blob_library.gni")
import("$dir_pw_build/python.gni")
import("$dir_pw_build/relative_source_file_names.gni")
import("$dir_pw_docgen/docs.gni")
import("$dir_pw_toolchain/traits.gni")
import("$dir_pw_unit_test/test.gni")
import("target_types.gni")

# IMPORTANT: The compilation flags in this file must be kept in sync with
Expand Down Expand Up @@ -231,3 +233,29 @@ pw_doc_group("docs") {
"python.rst",
]
}

pw_test("cc_blob_library_test") {
sources = [ "cc_blob_library_test.cc" ]
deps = [ ":test_blob" ]
}

pw_cc_blob_library("test_blob") {
out_header = "pw_build/test_blob.h"
namespace = "test::ns"
blobs = [
{
file_path = "test_blob_0123.bin"
symbol_name = "kFirstBlob0123"
alignas = 512
},
{
file_path = "test_blob_0123.bin"
symbol_name = "kSecondBlob0123"
},
]
visibility = [ ":*" ]
}

pw_test_group("tests") {
tests = [ ":cc_blob_library_test" ]
}
46 changes: 27 additions & 19 deletions pw_build/cc_blob_library.gni
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import("$dir_pw_build/python_action.gni")
import("$dir_pw_build/target_types.gni")

# Turns binary blobs into a C++ source_set library of hard-coded byte arrays.
# The byte arrays are constant initialized and are safe to access at any time,
# including before main().
#
# blobs A list of scopes, where each scope corresponds to a binary
# blob to be transformed from file to byte array. This is a
Expand All @@ -30,15 +32,21 @@ import("$dir_pw_build/target_types.gni")
# linker_section [optional]: If present, places the byte array
# in the specified linker section.
#
# alignas [optional]: If present, the byte array is aligned as
# specified. The value of this argument is used verbatim
# in an alignas() specifier for the blob byte array.
#
# out_header The header file to generate. Users will include this file
# exactly as it is written here to reference the byte arrays.
#
# namespace An optional (but highly recommended!) C++ namespace to place
# the generated blobs within.
# namespace The C++ namespace in which to place the generated blobs.
#
template("pw_cc_blob_library") {
assert(defined(invoker.blobs), "pw_cc_blob_library requires 'blobs'")
assert(defined(invoker.out_header),
"pw_cc_blob_library requires an 'out_header'")
assert(defined(invoker.namespace),
"pw_cc_blob_library requires a 'namespace'")

_blobs = []
_blob_files = []
Expand All @@ -50,9 +58,13 @@ template("pw_cc_blob_library") {
_blob_files += [ blob.file_path ]
}

_blob_json_file = "$target_gen_dir/$target_name.json"
_out_dir = "$target_gen_dir/$target_name"
_blob_json_file = "$_out_dir/blobs.json"
write_file(_blob_json_file, _blobs, "json")

_header = "$_out_dir/public/${invoker.out_header}"
_source = "$_out_dir/" + get_path_info(invoker.out_header, "name") + ".cc"

pw_python_action("$target_name._gen") {
forward_variables_from(invoker,
[
Expand All @@ -62,25 +74,17 @@ template("pw_cc_blob_library") {
module = "pw_build.generate_cc_blob_library"
python_deps = [ "$dir_pw_build/py" ]

_header = "${target_gen_dir}/public/" + invoker.out_header
_source =
"${target_gen_dir}/" + get_path_info(invoker.out_header, "name") + ".cc"
args = [
"--blob-file",
rebase_path(_blob_json_file, root_build_dir),
"--namespace=${invoker.namespace}",
"--header-include=${invoker.out_header}",
"--out-header",
rebase_path(_header),
rebase_path(_header, root_build_dir),
"--out-source",
rebase_path(_source),
rebase_path(_source, root_build_dir),
]

if (defined(invoker.namespace)) {
args += [
"--namespace",
invoker.namespace,
]
}

inputs = [ _blob_json_file ] + _blob_files
outputs = [
_header,
Expand All @@ -89,14 +93,18 @@ template("pw_cc_blob_library") {
}

config("$target_name._include_path") {
include_dirs = [ "${target_gen_dir}/public" ]
include_dirs = [ "$_out_dir/public" ]
visibility = [ ":*" ]
}

pw_source_set(target_name) {
sources = get_target_outputs(":$target_name._gen")
public = [ _header ]
sources = [ _source ]
public_configs = [ ":$target_name._include_path" ]
deps = [ ":$target_name._gen" ]
public_deps = [ "$dir_pw_preprocessor" ]
deps = [
":$target_name._gen",
dir_pw_preprocessor,
]
forward_variables_from(invoker, [ "visibility" ])
}
}
53 changes: 53 additions & 0 deletions pw_build/cc_blob_library_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2022 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include <cstddef>

#include "gtest/gtest.h"
#include "pw_build/test_blob.h"

namespace pw::build {
namespace {

static_assert(test::ns::kFirstBlob0123.size() == 4);
static_assert(test::ns::kFirstBlob0123.data() != nullptr);

static_assert(test::ns::kSecondBlob0123.size() == 4);
static_assert(test::ns::kSecondBlob0123.data() != nullptr);

TEST(CcBlobLibraryTest, FirstBlobContentsMatch) {
EXPECT_EQ(test::ns::kFirstBlob0123[0], std::byte{0});
EXPECT_EQ(test::ns::kFirstBlob0123[1], std::byte{1});
EXPECT_EQ(test::ns::kFirstBlob0123[2], std::byte{2});
EXPECT_EQ(test::ns::kFirstBlob0123[3], std::byte{3});
}

TEST(CcBlobLibraryTest, SecondBlobContentsMatch) {
EXPECT_EQ(test::ns::kSecondBlob0123[0], std::byte{0});
EXPECT_EQ(test::ns::kSecondBlob0123[1], std::byte{1});
EXPECT_EQ(test::ns::kSecondBlob0123[2], std::byte{2});
EXPECT_EQ(test::ns::kSecondBlob0123[3], std::byte{3});
}

TEST(CcBlobLibraryTest, FirstBlobAlignedTo512) {
// This checks that the variable is aligned to 512, but cannot guarantee that
// alignas was specified correctly, since it could be aligned to 512 by
// coincidence.
const uintptr_t addr = reinterpret_cast<uintptr_t>(&test::ns::kFirstBlob0123);
constexpr uintptr_t kAlignmentMask = static_cast<uintptr_t>(512 - 1);
EXPECT_EQ(addr & kAlignmentMask, 0u);
}

} // namespace
} // namespace pw::build
7 changes: 6 additions & 1 deletion pw_build/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ pw_cc_blob_library
The ``pw_cc_blob_library`` template is useful for embedding binary data into a
program. The template takes in a mapping of symbol names to file paths, and
generates a set of C++ source and header files that embed the contents of the
passed-in files as arrays.
passed-in files as arrays of ``std::byte``.

The blob byte arrays are constant initialized and are safe to access at any
time, including before ``main()``.

**Arguments**

Expand All @@ -140,6 +143,8 @@ passed-in files as arrays.
* ``file_path``: The file path for the binary blob.
* ``linker_section``: If present, places the byte array in the specified
linker section.
* ``alignas``: If present, uses the specified string or integer verbatim in
the ``alignas()`` specifier for the byte array.

* ``out_header``: The header file to generate. Users will include this file
exactly as it is written here to reference the byte arrays.
Expand Down
1 change: 1 addition & 0 deletions pw_build/generated_pigweed_modules_lists.gni
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ declare_args() {
"$dir_pw_blob_store:tests",
"$dir_pw_bluetooth:tests",
"$dir_pw_bluetooth_hci:tests",
"$dir_pw_build:tests",
"$dir_pw_bytes:tests",
"$dir_pw_checksum:tests",
"$dir_pw_chrono:tests",
Expand Down
Loading

0 comments on commit 867ddb8

Please sign in to comment.