aboutsummaryrefslogtreecommitdiff
path: root/pw_build/pigweed.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'pw_build/pigweed.bzl')
-rw-r--r--pw_build/pigweed.bzl320
1 files changed, 290 insertions, 30 deletions
diff --git a/pw_build/pigweed.bzl b/pw_build/pigweed.bzl
index 57274d488..2192445c6 100644
--- a/pw_build/pigweed.bzl
+++ b/pw_build/pigweed.bzl
@@ -13,46 +13,47 @@
# the License.
"""Pigweed build environment for bazel."""
+load("@bazel_skylib//lib:selects.bzl", "selects")
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
+load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
load(
"//pw_build/bazel_internal:pigweed_internal.bzl",
- _add_defaults = "add_defaults",
+ _compile_cc = "compile_cc",
)
+# Used by `pw_cc_test`.
+FUZZTEST_OPTS = [
+ "-Wno-sign-compare",
+ "-Wno-unused-parameter",
+]
+
def pw_cc_binary(**kwargs):
"""Wrapper for cc_binary providing some defaults.
- Specifically, this wrapper,
-
- * Adds default copts.
- * Adds a dep on the pw_assert backend.
- * Sets "linkstatic" to True.
- * Disables header modules (via the feature -use_header_modules).
+ Specifically, this wrapper adds deps on backend_impl targets for pw_assert
+ and pw_log.
Args:
**kwargs: Passed to cc_binary.
"""
kwargs["deps"] = kwargs.get("deps", [])
- # TODO(b/234877642): Remove this implicit dependency once we have a better
+ # TODO: b/234877642 - Remove this implicit dependency once we have a better
# way to handle the facades without introducing a circular dependency into
# the build.
- kwargs["deps"] = kwargs["deps"] + ["@pigweed_config//:pw_assert_backend"]
- _add_defaults(kwargs)
+ kwargs["deps"] = kwargs["deps"] + ["@pigweed//targets:pw_assert_backend_impl"]
+ kwargs["deps"] = kwargs["deps"] + ["@pigweed//pw_log:backend_impl"]
native.cc_binary(**kwargs)
def pw_cc_library(**kwargs):
- """Wrapper for cc_library providing some defaults.
-
- Specifically, this wrapper,
+ """Wrapper for cc_library.
- * Adds default copts.
- * Sets "linkstatic" to True.
- * Disables header modules (via the feature -use_header_modules).
+ TODO: b/267498492 - This wrapper no longer does anything. Remove it once
+ all projects have been migrated off of it.
Args:
**kwargs: Passed to cc_library.
"""
- _add_defaults(kwargs)
native.cc_library(**kwargs)
def pw_cc_test(**kwargs):
@@ -60,43 +61,75 @@ def pw_cc_test(**kwargs):
Specifically, this wrapper,
- * Adds default copts.
* Adds a dep on the pw_assert backend.
* Adds a dep on //pw_unit_test:simple_printing_main
- * Sets "linkstatic" to True.
- * Disables header modules (via the feature -use_header_modules).
+
+ In addition, a .lib target is created that's a cc_library with the same
+ kwargs. Such library targets can be used as dependencies of firmware images
+ bundling multiple tests. The library target has alwayslink = 1, to support
+ dynamic registration (ensure the tests are baked into the image even though
+ there are no references to them, so that they can be found by RUN_ALL_TESTS
+ at runtime).
Args:
**kwargs: Passed to cc_test.
"""
kwargs["deps"] = kwargs.get("deps", []) + \
- ["@pigweed//pw_unit_test:simple_printing_main"]
+ ["@pigweed//targets:pw_unit_test_main"]
- # TODO(b/234877642): Remove this implicit dependency once we have a better
+ # TODO: b/234877642 - Remove this implicit dependency once we have a better
# way to handle the facades without introducing a circular dependency into
# the build.
- kwargs["deps"] = kwargs["deps"] + ["@pigweed_config//:pw_assert_backend"]
- _add_defaults(kwargs)
+ kwargs["deps"] = kwargs["deps"] + ["@pigweed//targets:pw_assert_backend_impl"]
+
+ # Some tests may include FuzzTest, which includes headers that trigger
+ # warnings. This check must be done here and not in `add_defaults`, since
+ # the `use_fuzztest` config setting can refer by label to a library which
+ # itself calls `add_defaults`.
+ extra_copts = select({
+ "@pigweed//pw_fuzzer:use_fuzztest": FUZZTEST_OPTS,
+ "//conditions:default": [],
+ })
+ kwargs["copts"] = kwargs.get("copts", []) + extra_copts
+
native.cc_test(**kwargs)
+ kwargs["alwayslink"] = 1
+
+ # pw_cc_test deps may include testonly targets.
+ kwargs["testonly"] = True
+
+ # Remove any kwargs that cc_library would not recognize.
+ for arg in (
+ "additional_linker_inputs",
+ "args",
+ "env",
+ "env_inherit",
+ "flaky",
+ "local",
+ "malloc",
+ "shard_count",
+ "size",
+ "stamp",
+ "timeout",
+ ):
+ kwargs.pop(arg, "")
+ native.cc_library(name = kwargs.pop("name") + ".lib", **kwargs)
+
def pw_cc_perf_test(**kwargs):
"""A Pigweed performance test.
This macro produces a cc_binary and,
- * Adds default copts.
* Adds a dep on the pw_assert backend.
* Adds a dep on //pw_perf_test:logging_main
- * Sets "linkstatic" to True.
- * Disables header modules (via the feature -use_header_modules).
Args:
**kwargs: Passed to cc_binary.
"""
kwargs["deps"] = kwargs.get("deps", []) + \
["@pigweed//pw_perf_test:logging_main"]
- kwargs["deps"] = kwargs["deps"] + ["@pigweed_config//:pw_assert_backend"]
- _add_defaults(kwargs)
+ kwargs["deps"] = kwargs["deps"] + ["@pigweed//targets:pw_assert_backend_impl"]
native.cc_binary(**kwargs)
def pw_cc_facade(**kwargs):
@@ -109,5 +142,232 @@ def pw_cc_facade(**kwargs):
if "srcs" in kwargs.keys():
fail("'srcs' attribute does not exist in pw_cc_facade, please use \
main implementing target.")
- _add_defaults(kwargs)
native.cc_library(**kwargs)
+
+def host_backend_alias(name, backend):
+ """An alias that resolves to the backend for host platforms."""
+ native.alias(
+ name = name,
+ actual = selects.with_or({
+ (
+ "@platforms//os:android",
+ "@platforms//os:chromiumos",
+ "@platforms//os:linux",
+ "@platforms//os:macos",
+ "@platforms//os:windows",
+ ): backend,
+ "//conditions:default": "@pigweed//pw_build:unspecified_backend",
+ }),
+ )
+
+CcBlobInfo = provider(
+ "Input to pw_cc_blob_library",
+ fields = {
+ "symbol_name": "The C++ symbol for the byte array.",
+ "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, the byte array is aligned as specified. The " +
+ "value of this argument is used verbatim in an alignas() " +
+ "specifier for the blob byte array.",
+ },
+)
+
+def _pw_cc_blob_info_impl(ctx):
+ return [CcBlobInfo(
+ symbol_name = ctx.attr.symbol_name,
+ file_path = ctx.file.file_path,
+ linker_section = ctx.attr.linker_section,
+ alignas = ctx.attr.alignas,
+ )]
+
+pw_cc_blob_info = rule(
+ implementation = _pw_cc_blob_info_impl,
+ attrs = {
+ "symbol_name": attr.string(),
+ "file_path": attr.label(allow_single_file = True),
+ "linker_section": attr.string(default = ""),
+ "alignas": attr.string(default = ""),
+ },
+ provides = [CcBlobInfo],
+)
+
+def _pw_cc_blob_library_impl(ctx):
+ # Python tool takes a json file with info about blobs to generate.
+ blobs = []
+ blob_paths = []
+ for blob in ctx.attr.blobs:
+ blob_info = blob[CcBlobInfo]
+ blob_paths.append(blob_info.file_path)
+ blob_dict = {
+ "file_path": blob_info.file_path.path,
+ "symbol_name": blob_info.symbol_name,
+ "linker_section": blob_info.linker_section,
+ }
+ if (blob_info.alignas):
+ blob_dict["alignas"] = blob_info.alignas
+ blobs.append(blob_dict)
+ blob_json = ctx.actions.declare_file(ctx.label.name + "_blob.json")
+ ctx.actions.write(blob_json, json.encode(blobs))
+
+ hdr = ctx.actions.declare_file(ctx.attr.out_header)
+ src = ctx.actions.declare_file(ctx.attr.out_header.removesuffix(".h") + ".cc")
+
+ if (not ctx.attr.namespace):
+ fail("namespace required for pw_cc_blob_library")
+
+ args = ctx.actions.args()
+ args.add("--blob-file={}".format(blob_json.path))
+ args.add("--namespace={}".format(ctx.attr.namespace))
+ args.add("--header-include={}".format(ctx.attr.out_header))
+ args.add("--out-header={}".format(hdr.path))
+ args.add("--out-source={}".format(src.path))
+
+ ctx.actions.run(
+ inputs = depset(direct = blob_paths + [blob_json]),
+ progress_message = "Generating cc blob library for %s" % (ctx.label.name),
+ tools = [
+ ctx.executable._generate_cc_blob_library,
+ ctx.executable._python_runtime,
+ ],
+ outputs = [hdr, src],
+ executable = ctx.executable._generate_cc_blob_library,
+ arguments = [args],
+ )
+
+ return _compile_cc(
+ ctx,
+ [src],
+ [hdr],
+ deps = ctx.attr.deps,
+ includes = [ctx.bin_dir.path + "/" + ctx.label.package],
+ defines = [],
+ )
+
+pw_cc_blob_library = rule(
+ implementation = _pw_cc_blob_library_impl,
+ doc = """Turns binary blobs into a C++ library of hard-coded byte arrays.
+
+ The byte arrays are constant initialized and are safe to access at any time,
+ including before main().
+
+ Args:
+ ctx: Rule context.
+ blobs: A list of CcBlobInfo where each entry corresponds to a binary
+ blob to be transformed from file to byte array. This is a
+ required field. Blob fields include:
+
+ symbol_name [required]: The C++ symbol for the byte array.
+
+ file_path [required]: The file path for the binary blob.
+
+ 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: The C++ namespace in which to place the generated blobs.
+ """,
+ attrs = {
+ "blobs": attr.label_list(providers = [CcBlobInfo]),
+ "out_header": attr.string(),
+ "namespace": attr.string(),
+ "_python_runtime": attr.label(
+ default = Label("//:python3_interpreter"),
+ allow_single_file = True,
+ executable = True,
+ cfg = "exec",
+ ),
+ "_generate_cc_blob_library": attr.label(
+ default = Label("//pw_build/py:generate_cc_blob_library"),
+ executable = True,
+ cfg = "exec",
+ ),
+ "deps": attr.label_list(default = [Label("//pw_preprocessor")]),
+ },
+ provides = [CcInfo],
+ fragments = ["cpp"],
+ toolchains = use_cpp_toolchain(),
+)
+
+def _preprocess_linker_script_impl(ctx):
+ cc_toolchain = find_cpp_toolchain(ctx)
+ output_script = ctx.actions.declare_file(ctx.label.name + ".ld")
+ feature_configuration = cc_common.configure_features(
+ ctx = ctx,
+ cc_toolchain = cc_toolchain,
+ requested_features = ctx.features,
+ unsupported_features = ctx.disabled_features,
+ )
+ cxx_compiler_path = cc_common.get_tool_for_action(
+ feature_configuration = feature_configuration,
+ action_name = C_COMPILE_ACTION_NAME,
+ )
+ c_compile_variables = cc_common.create_compile_variables(
+ feature_configuration = feature_configuration,
+ cc_toolchain = cc_toolchain,
+ user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts,
+ )
+ env = cc_common.get_environment_variables(
+ feature_configuration = feature_configuration,
+ action_name = C_COMPILE_ACTION_NAME,
+ variables = c_compile_variables,
+ )
+ ctx.actions.run(
+ outputs = [output_script],
+ inputs = depset(
+ [ctx.file.linker_script],
+ transitive = [cc_toolchain.all_files],
+ ),
+ executable = cxx_compiler_path,
+ arguments = [
+ "-E",
+ "-P",
+ # TODO: b/296928739 - This flag is needed so cc1 can be located
+ # despite the presence of symlinks. Normally this is provided
+ # through copts inherited from the toolchain, but since those are
+ # not pulled in here the flag must be explicitly added.
+ "-no-canonical-prefixes",
+ "-xc",
+ ctx.file.linker_script.path,
+ "-o",
+ output_script.path,
+ ] + [
+ "-D" + d
+ for d in ctx.attr.defines
+ ] + ctx.attr.copts,
+ env = env,
+ )
+ linker_input = cc_common.create_linker_input(
+ owner = ctx.label,
+ user_link_flags = ["-T", output_script.path],
+ additional_inputs = depset(direct = [output_script]),
+ )
+ linking_context = cc_common.create_linking_context(
+ linker_inputs = depset(direct = [linker_input]),
+ )
+ return [
+ DefaultInfo(files = depset([output_script])),
+ CcInfo(linking_context = linking_context),
+ ]
+
+pw_linker_script = rule(
+ _preprocess_linker_script_impl,
+ attrs = {
+ "copts": attr.string_list(doc = "C compile options."),
+ "defines": attr.string_list(doc = "C preprocessor defines."),
+ "linker_script": attr.label(
+ mandatory = True,
+ allow_single_file = True,
+ doc = "Linker script to preprocess.",
+ ),
+ "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
+ },
+ toolchains = use_cpp_toolchain(),
+ fragments = ["cpp"],
+)