blob: a4277b653e7b006ea794f2c167362471570a33a4 [file] [edit]
# Copyright 2026 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.
"""Repository rule for app-board specific Zephyr configuration. (forced update)"""
load("//:naming.bzl", "normalize_app_label")
load("//bazel/private:kconfig_args.bzl", "get_kconfig_args")
load("//bazel/private:repo_rule_python.bzl", "COMMON_PY_REPO_RULE_ATTRS", "get_python")
def _gen_zephyr_config_impl(rctx):
rctx.watch(rctx.attr.state_file)
state_file = rctx.path(rctx.attr.state_file)
state = json.decode(rctx.read(state_file))
zephyr_root_path = str(rctx.path(Label(state["zephyr_root"])).dirname)
# Robust normalization: strip repo and redundant target name
norm_app = normalize_app_label(rctx.attr.app_label)
app_dir_label = state["apps"].get(norm_app)
if not app_dir_label:
fail("App %s (normalized: %s) not found in discovery index. Discovered: %s" % (rctx.attr.app_label, norm_app, state["apps"].keys()))
app_dir_path = str(rctx.path(Label(app_dir_label)).dirname)
board_dir_label = state["board_index"].get(rctx.attr.board_id)
if not board_dir_label:
fail("Board %s not found in discovery index" % rctx.attr.board_id)
board_dir_path = str(rctx.path(Label(board_dir_label)).dirname)
resolved_oot_dts_roots = [str(rctx.path(Label(l)).dirname) for l in state.get("oot_dts_roots", [])]
resolved_modules = []
for m_label_str in state["modules"].values():
m_label = Label(m_label_str)
m_path = rctx.path(m_label)
if m_path.basename == "module.yml" and m_path.dirname.basename == "zephyr":
mod_root = m_path.dirname.dirname
else:
mod_root = m_path.dirname
resolved_modules.append(str(mod_root))
kconfig_gen_values_py = rctx.path(rctx.attr._kconfig_gen_values_py)
kconfig_utils_py = rctx.path(Label("//scripts/build:kconfig_utils.py"))
rctx.watch(kconfig_utils_py)
python = get_python(rctx, extra_import_paths = [
zephyr_root_path + "/scripts/kconfig",
str(kconfig_gen_values_py.dirname),
])
rctx.watch(kconfig_gen_values_py)
rctx.watch(rctx.path(Label("//scripts/build:kconfig_utils.py")))
# Watch application configuration files
if app_dir_path:
# Recursively watch the app directory to catch created configuration files.
rctx.watch_tree(rctx.path(app_dir_path))
if board_dir_path:
rctx.watch_tree(rctx.path(board_dir_path))
resolved_conf_fragments = []
for fragment in rctx.attr.conf_fragments:
if not fragment.startswith("/"):
fragment_path = rctx.path(str(rctx.workspace_root) + "/" + fragment)
else:
fragment_path = rctx.path(fragment)
rctx.watch(fragment_path)
resolved_conf_fragments.append(str(fragment_path))
if rctx.attr.extra_kconfig:
rctx.file("sysbuild_generated.conf", rctx.attr.extra_kconfig)
resolved_conf_fragments.append(str(rctx.path("sysbuild_generated.conf")))
args = get_kconfig_args(
script = kconfig_gen_values_py,
zephyr_root = zephyr_root_path,
modules = resolved_modules,
app_dir = app_dir_path,
board = rctx.attr.board_id,
board_dir = board_dir_path,
parent_platform = rctx.attr.parent_platform,
output_dir = ".",
app_name = rctx.attr.app_label.name,
oot_dts_roots = resolved_oot_dts_roots,
conf_fragments = resolved_conf_fragments,
)
result = python.execute(args)
if result.return_code != 0:
fail("Zephyr config generation failed: %s" % result.stderr)
# We need to replace @zc_target with the actual repo name in BUILD.bazel
# since the script doesn't know it.
build_bazel = rctx.read("BUILD.bazel")
build_bazel = build_bazel.replace("@zc_target", "@@" + rctx.name)
rctx.file("BUILD.bazel", build_bazel)
gen_zephyr_config = repository_rule(
implementation = _gen_zephyr_config_impl,
attrs = {
"app_label": attr.label(mandatory = True),
"board_id": attr.string(mandatory = True),
"parent_platform": attr.label(mandatory = True),
"state_file": attr.label(mandatory = True),
"conf_fragments": attr.string_list(),
"extra_kconfig": attr.string(),
"_kconfig_gen_values_py": attr.label(default = "//scripts/build:kconfig_gen_values.py"),
} | COMMON_PY_REPO_RULE_ATTRS,
)