|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v3 012/114] target-info: add TargetKconfig
Add a packed TargetKconfig of device and accel CONFIG_* bits,
generated from the Kconfig tree, and attach it to TargetInfo.
target_kconfig() returns the current bits, and
target_has_kconfig_<name>() tests them. Initialize
target_info_stub.kconfig from CONFIG_DEVICES.
Signed-off-by: Yonggang Luo <luoyonggang@xxxxxxxxx>
---
include/qemu/target-info-def.h | 2 +
include/qemu/target-kconfig-has.h | 7 ++
include/qemu/target-kconfig.h | 34 ++++++
meson.build | 14 +++
scripts/gen-target-kconfig.py | 162 +++++++++++++++++++++++++++
target-info-def.c | 6 +
target-kconfig.c | 20 ++++
tests/unit/meson.build | 1 +
tests/unit/test-target-kconfig-has.c | 22 ++++
9 files changed, 268 insertions(+)
create mode 100644 include/qemu/target-kconfig-has.h
create mode 100644 include/qemu/target-kconfig.h
create mode 100644 scripts/gen-target-kconfig.py
create mode 100644 target-kconfig.c
create mode 100644 tests/unit/test-target-kconfig-has.c
diff --git a/include/qemu/target-info-def.h b/include/qemu/target-info-def.h
index 25dc7c508d3..615596ed468 100644
--- a/include/qemu/target-info-def.h
+++ b/include/qemu/target-info-def.h
@@ -13,6 +13,7 @@
#include "qapi/qapi-types-machine.h"
#include "qemu/queue.h"
#include "qemu/target-info.h"
+#include "qemu/target-kconfig.h"
struct TargetInfo {
/* runtime equivalent of TARGET_NAME definition */
@@ -32,6 +33,7 @@ struct TargetInfo {
unsigned page_bits_init;
/* runtime equivalent of TARGET_PAGE_BITS_VARY definition */
bool page_bits_vary;
+ TargetKconfig kconfig;
};
typedef struct TargetInfoNode TargetInfoNode;
diff --git a/include/qemu/target-kconfig-has.h
b/include/qemu/target-kconfig-has.h
new file mode 100644
index 00000000000..6616f75845a
--- /dev/null
+++ b/include/qemu/target-kconfig-has.h
@@ -0,0 +1,7 @@
+/*
+ * QEMU target_has_kconfig_* helpers
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "target-kconfig-has-gen.h"
diff --git a/include/qemu/target-kconfig.h b/include/qemu/target-kconfig.h
new file mode 100644
index 00000000000..21b2ba576ec
--- /dev/null
+++ b/include/qemu/target-kconfig.h
@@ -0,0 +1,34 @@
+/*
+ * QEMU target kconfig API
+ *
+ * Copyright (c) Yonggang Luo
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_TARGET_KCONFIG_H
+#define QEMU_TARGET_KCONFIG_H
+
+#include "qemu/compiler.h"
+
+/**
+ * struct TargetKconfig:
+ *
+ * Compile-time device and accel CONFIG_* bits. Not Kconfig.host
+ * or target/Kconfig. Target identity is TargetInfo, not these
+ * bits. Not kvm_enabled() etc. Fields and
+ * target_has_kconfig_<name>() are generated by
+ * scripts/gen-target-kconfig.py.
+ */
+typedef struct TargetKconfig {
+#include "target-kconfig-fields.h"
+} QEMU_PACKED TargetKconfig;
+
+/**
+ * target_kconfig:
+ *
+ * Returns: The current TargetKconfig (target_info()->kconfig).
+ */
+const TargetKconfig *target_kconfig(void);
+
+#endif
diff --git a/meson.build b/meson.build
index 776d38c5afd..8a017faaa74 100644
--- a/meson.build
+++ b/meson.build
@@ -3445,6 +3445,19 @@ genh += custom_target('config-poison.h',
capture: true,
command: [find_program('scripts/make-config-poison.sh'),
target_configs_h])
+genh += custom_target('target-kconfig',
+ output: ['target-kconfig-fields.h',
+ 'target-kconfig-init.h',
+ 'target-kconfig-has-gen.h',
+ 'target-kconfig-has.c.inc'],
+ depfile: 'target-kconfig.d',
+ command: [python, files('scripts/gen-target-kconfig.py'),
+ '--kconfig', meson.current_source_dir() /
'Kconfig',
+ '--depfile', '@DEPFILE@',
+ '--fields', '@OUTPUT0@',
+ '--init', '@OUTPUT1@',
+ '--has', '@OUTPUT2@',
+ '--has-c', '@OUTPUT3@'])
if fdt_required.length() > 0
error('fdt disabled but required by targets ' + ', '.join(fdt_required))
@@ -3779,6 +3792,7 @@ endif
qom_ss.add(files(
'target-info.c',
+ 'target-kconfig.c',
))
qom_ss = qom_ss.apply({})
libqom = static_library('qom', qom_ss.sources() + genh,
diff --git a/scripts/gen-target-kconfig.py b/scripts/gen-target-kconfig.py
new file mode 100644
index 00000000000..afeffc75ca0
--- /dev/null
+++ b/scripts/gen-target-kconfig.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+"""Generate TargetKconfig CONFIG_* field, initializer, and has headers.
+
+The field list is every `config FOO` from the QEMU Kconfig tree,
+parsed with scripts/minikconf.py (including accel/Kconfig: KVM,
+XEN, HVF, TCG, ...). Host proxies in Kconfig.host and the
+target/Kconfig tree (arch tokens and TARGET_BIG_ENDIAN) are
+omitted. Target identity is TargetInfo, not TargetKconfig.
+
+Each field also gets target_has_kconfig_<name>(const TargetInfo *).
+"""
+
+import argparse
+import os
+import sys
+
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+from minikconf import KconfigData, KconfigParser
+
+
+def field_name(config: str) -> str:
+ return config[len("CONFIG_"):].lower()
+
+
+def collect_from_kconfig(root: str) -> tuple[set[str], list[str]]:
+ data = KconfigData()
+ with open(root, "rt", encoding="utf-8") as fp:
+ KconfigParser.parse(fp, data)
+ names = {"CONFIG_" + name for name in data.defined_vars}
+ return names, list(data.previously_included)
+
+
+def collect_kconfig_names(path: str) -> set[str]:
+ data = KconfigData()
+ with open(path, "rt", encoding="utf-8") as fp:
+ KconfigParser.parse(fp, data)
+ return {"CONFIG_" + name for name in data.defined_vars}
+
+
+def collect_host_kconfig_names(kconfig_root: str) -> set[str]:
+ host = os.path.join(os.path.dirname(os.path.abspath(kconfig_root)),
+ "Kconfig.host")
+ return collect_kconfig_names(host)
+
+
+def collect_target_kconfig_names(kconfig_root: str) -> set[str]:
+ target = os.path.join(os.path.dirname(os.path.abspath(kconfig_root)),
+ "target", "Kconfig")
+ return collect_kconfig_names(target)
+
+
+def write_fields(path: str, configs: list[str]) -> None:
+ lines = [
+ "/* Generated by scripts/gen-target-kconfig.py. Do not edit. */",
+ "",
+ ]
+ for name in configs:
+ lines.append(f" uint32_t {field_name(name)} : 1;")
+ lines.append("")
+ with open(path, "w", encoding="utf-8", newline="\n") as fh:
+ fh.write("\n".join(lines))
+
+
+def write_init(path: str, configs: list[str]) -> None:
+ lines = [
+ "/* Generated by scripts/gen-target-kconfig.py. Do not edit. */",
+ "",
+ ]
+ for name in configs:
+ field = field_name(name)
+ lines.append(f"#if defined({name})")
+ lines.append(f" .{field} = true,")
+ lines.append("#endif")
+ lines.append("")
+ with open(path, "w", encoding="utf-8", newline="\n") as fh:
+ fh.write("\n".join(lines))
+
+
+def has_fn(config: str) -> str:
+ return "target_has_kconfig_" + field_name(config)
+
+
+def write_has_h(path: str, configs: list[str]) -> None:
+ lines = [
+ "/* Generated by scripts/gen-target-kconfig.py. Do not edit. */",
+ "",
+ "#ifndef TARGET_KCONFIG_HAS_GEN_H",
+ "#define TARGET_KCONFIG_HAS_GEN_H",
+ "",
+ "#include <stdbool.h>",
+ "",
+ "typedef struct TargetInfo TargetInfo;",
+ "",
+ ]
+ for name in configs:
+ lines.append(f"bool {has_fn(name)}(const TargetInfo *ti);")
+ lines.append("")
+ lines.append("#endif")
+ lines.append("")
+ with open(path, "w", encoding="utf-8", newline="\n") as fh:
+ fh.write("\n".join(lines))
+
+
+def write_has_c(path: str, configs: list[str]) -> None:
+ lines = [
+ "/* Generated by scripts/gen-target-kconfig.py. Do not edit. */",
+ "",
+ ]
+ for name in configs:
+ fn = has_fn(name)
+ field = field_name(name)
+ lines.append(f"bool {fn}(const TargetInfo *ti)")
+ lines.append("{")
+ lines.append(f" return ti->kconfig.{field};")
+ lines.append("}")
+ lines.append("")
+ with open(path, "w", encoding="utf-8", newline="\n") as fh:
+ fh.write("\n".join(lines))
+
+
+def write_depfile(path: str, outputs: list[str], deps: list[str]) -> None:
+ lines = [" ".join(outputs) + ":" ]
+ for dep in deps:
+ lines.append(f" {dep} \\")
+ if len(lines) > 1:
+ lines[-1] = lines[-1][:-2]
+ lines.append("")
+ with open(path, "w", encoding="utf-8", newline="\n") as fh:
+ fh.write("\n".join(lines))
+
+
+def main(argv: list[str]) -> int:
+ parser = argparse.ArgumentParser(
+ description="Generate TargetKconfig CONFIG_* include headers"
+ )
+ parser.add_argument("--fields", required=True, help="output fields header")
+ parser.add_argument("--init", required=True, help="output initializer
header")
+ parser.add_argument("--has", required=True, help="output has-function
header")
+ parser.add_argument("--has-c", required=True, help="output has-function
bodies")
+ parser.add_argument("--kconfig", required=True, help="root Kconfig")
+ parser.add_argument("--depfile", help="ninja depfile of walked Kconfig
files")
+ args = parser.parse_args(argv)
+
+ names, kconfig_files = collect_from_kconfig(args.kconfig)
+ names -= collect_host_kconfig_names(args.kconfig)
+ names -= collect_target_kconfig_names(args.kconfig)
+ configs = sorted(names)
+
+ write_fields(args.fields, configs)
+ write_init(args.init, configs)
+ write_has_h(args.has, configs)
+ write_has_c(args.has_c, configs)
+ if args.depfile:
+ write_depfile(args.depfile,
+ [args.fields, args.init, args.has, args.has_c],
+ kconfig_files)
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))
diff --git a/target-info-def.c b/target-info-def.c
index 954298b56d0..44d153cefbc 100644
--- a/target-info-def.c
+++ b/target-info-def.c
@@ -7,6 +7,9 @@
*/
#include "qemu/osdep.h"
+#ifdef CONFIG_DEVICES
+#include CONFIG_DEVICES
+#endif
#include "qemu/target-info.h"
#include "qemu/target-info-def.h"
#include "cpu-qom.h"
@@ -33,6 +36,9 @@ static const TargetInfo target_info_stub = {
.page_bits_vary = false,
.page_bits_init = TARGET_PAGE_BITS,
#endif
+ .kconfig = {
+#include "target-kconfig-init.h"
+ },
};
target_info_init(target_info_stub)
diff --git a/target-kconfig.c b/target-kconfig.c
new file mode 100644
index 00000000000..078c0d8e7f3
--- /dev/null
+++ b/target-kconfig.c
@@ -0,0 +1,20 @@
+/*
+ * QEMU target kconfig helpers
+ *
+ * Copyright (c) Yonggang Luo
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/target-info.h"
+#include "qemu/target-info-def.h"
+#include "qemu/target-kconfig.h"
+#include "qemu/target-kconfig-has.h"
+
+const TargetKconfig *target_kconfig(void)
+{
+ return &target_info()->kconfig;
+}
+
+#include "target-kconfig-has.c.inc"
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index dc980a35955..c806dbc4ffa 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -47,6 +47,7 @@ tests = {
objects: target_info_def_objects.values(),
compile_args: ['-DTARGET_INFO_DEF_COUNT=@0@'.format(
target_info_def_objects.values().length())])],
+ 'test-target-kconfig-has': [qom],
'test-qemu-opts': [],
'test-keyval': [testqapi],
'test-logging': [],
diff --git a/tests/unit/test-target-kconfig-has.c
b/tests/unit/test-target-kconfig-has.c
new file mode 100644
index 00000000000..289ed89b854
--- /dev/null
+++ b/tests/unit/test-target-kconfig-has.c
@@ -0,0 +1,22 @@
+/*
+ * target-kconfig-has.h include path test
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/target-kconfig-has.h"
+
+static void test_include(void)
+{
+ bool (*fn)(const TargetInfo *ti) = target_has_kconfig_tcg;
+
+ g_assert_nonnull(fn);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/target-kconfig-has/include", test_include);
+ return g_test_run();
+}
--
2.52.0.windows.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |