blob: d49a5839fb3866c22c751756d487c400668d6a22 [file] [log] [blame]
# Copyright 2025 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.
import argparse
import pathlib
import sys
import kconfiglib
def write_kconfig_build_file(
ostream,
kconfig: kconfiglib.Kconfig,
) -> None:
ostream.write("""load("@bazel_skylib//rules:common_settings.bzl",
"bool_flag",
"int_flag",
"string_flag",
)
package(default_visibility = ["//visibility:public"])
""")
for sym_name, sym in kconfig.syms.items():
if sym is None or sym.type == kconfiglib.UNKNOWN:
continue
for sym_str in str(sym).splitlines():
ostream.write(f"# {sym_str}\n")
if sym.type == kconfiglib.INT or sym.type == kconfiglib.HEX:
ostream.write(f"""int_flag(
name = "CONFIG_{sym_name}",
build_setting_default=0,
visibility = ["//visibility:public"],
)
""")
elif sym.type == kconfiglib.BOOL:
ostream.write(f"""bool_flag(
name = "CONFIG_{sym_name}",
build_setting_default=False,
visibility = ["//visibility:public"],
)
config_setting(
name = "CONFIG_{sym_name}=true",
flag_values = {{
":CONFIG_{sym_name}": "true",
}},
)
""")
elif sym.type == kconfiglib.STRING:
ostream.write(f"""string_flag(
name = "CONFIG_{sym_name}",
build_setting_default="",
visibility = ["//visibility:public"],
)
""")
def write_project_build_file(
ostream,
kconfig: kconfiglib.Kconfig,
) -> None:
ostream.write("KCONFIG_FLAGS = [\n")
for sym in kconfig.unique_defined_syms:
if sym is None or sym.type == kconfiglib.UNKNOWN:
continue
name = f"@kconfig//:CONFIG_{sym.name}"
if sym.type == kconfiglib.INT or sym.type == kconfiglib.HEX:
value = sym.str_value
if value == "":
value = "0"
elif sym.type == kconfiglib.BOOL:
value = "true" if sym.str_value == 'y' else "false"
elif sym.type == kconfiglib.STRING:
value = f'\\"{sym.str_value}\\"'
else:
raise RuntimeError(f"Unsupported symbol type: {sym.type}")
ostream.write(f" \"--{name}={value}\",\n")
ostream.write("]\n")
# Creates a list of options from Kconfig symbols without concerning their
# values in a project.
def generate_kconfig_build_file(
kconfig_path: pathlib.Path,
out: pathlib.Path | None,
) -> None:
print("Loading Kconfig file: " + str(kconfig_path))
kconfig = kconfiglib.Kconfig(filename=kconfig_path)
if out:
with open(out, "w", encoding="utf-8") as f:
write_kconfig_build_file(ostream=f, kconfig=kconfig)
else:
write_kconfig_build_file(ostream=sys.stdout, kconfig=kconfig)
def generate_project_build_file(
kconfig_path: pathlib.Path,
project_path: pathlib.Path,
extra_conf_files: list[pathlib.Path],
out: pathlib.Path | None,
) -> None:
print("Loading Kconfig file: " + str(kconfig_path))
kconfig = kconfiglib.Kconfig(filename=kconfig_path)
kconfig.load_config(filename=project_path)
for conf_file in extra_conf_files:
print(kconfig.load_config(conf_file, replace=False))
if out:
with open(out, "w", encoding="utf-8") as f:
write_project_build_file(ostream=f, kconfig=kconfig)
else:
write_project_build_file(ostream=sys.stdout, kconfig=kconfig)
kconfig.write_autoconf("generated/zephyr/autoconf.h")
def main() -> None:
parser = argparse.ArgumentParser(description="Kconfig bazel port")
parser.add_argument(
"--kconfig",
type=pathlib.Path,
help="Root Kconfig file to load",
required=True,
)
subparsers = parser.add_subparsers(
dest="subcommand",
required=True,
)
gen_kconfig_parser = subparsers.add_parser(
"gen_kconfig",
help="Generate generic kconfig BUILD",
)
gen_kconfig_parser.add_argument(
"-o",
type=pathlib.Path,
help="Output file",
)
gen_project_parser = subparsers.add_parser(
"gen_project",
help="Generate BUILD file for a specific peroject",
)
gen_project_parser.add_argument(
"--project",
type=pathlib.Path,
help="Project config file",
)
gen_project_parser.add_argument(
"-o",
type=pathlib.Path,
help="Output file",
)
gen_project_parser.add_argument(
"--extra_configs_in",
type=pathlib.Path,
nargs="*",
help="Input configuration fragments. Will be merged together.",
)
args = parser.parse_args()
kconfig_path = args.kconfig
subcommand = args.subcommand
if subcommand == "gen_kconfig":
generate_kconfig_build_file(
kconfig_path=kconfig_path,
out=args.o,
)
elif subcommand == "gen_project":
generate_project_build_file(
kconfig_path=kconfig_path,
project_path=args.project,
extra_conf_files=args.extra_configs_in,
out=args.o,
)
else:
parser.print_help()
if __name__ == "__main__":
main()