diff mbox series

[v3,03/24] modules: generate modinfo.c

Message ID 20210618045353.2510174-4-kraxel@redhat.com (mailing list archive)
State New, archived
Headers show
Series modules: add meta-data database | expand

Commit Message

Gerd Hoffmann June 18, 2021, 4:53 a.m. UTC
Add script to generate C source with a small
database containing the module meta-data.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 scripts/modinfo-generate.py | 84 +++++++++++++++++++++++++++++++++++++
 include/qemu/module.h       | 17 ++++++++
 softmmu/vl.c                |  4 ++
 util/module.c               | 11 +++++
 meson.build                 | 13 +++++-
 5 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100755 scripts/modinfo-generate.py

Comments

Jose R. Ziviani June 22, 2021, 6:19 p.m. UTC | #1
Hello,

Just a small change.

On Fri, Jun 18, 2021 at 06:53:32AM +0200, Gerd Hoffmann wrote:
> Add script to generate C source with a small
> database containing the module meta-data.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  scripts/modinfo-generate.py | 84 +++++++++++++++++++++++++++++++++++++
>  include/qemu/module.h       | 17 ++++++++
>  softmmu/vl.c                |  4 ++
>  util/module.c               | 11 +++++
>  meson.build                 | 13 +++++-
>  5 files changed, 128 insertions(+), 1 deletion(-)
>  create mode 100755 scripts/modinfo-generate.py
> 
> diff --git a/scripts/modinfo-generate.py b/scripts/modinfo-generate.py
> new file mode 100755
> index 000000000000..2b925432655a
> --- /dev/null
> +++ b/scripts/modinfo-generate.py
> @@ -0,0 +1,84 @@
> +#!/usr/bin/env python3
> +# -*- coding: utf-8 -*-
> +
> +import os
> +import sys
> +
> +def print_array(name, values):
> +    if len(values) == 0:
> +        return
> +    list = ", ".join(values)
> +    print("    .%s = ((const char*[]){ %s, NULL })," % (name, list))
> +
> +def parse_line(line):
> +    kind = ""
> +    data = ""
> +    get_kind = False
> +    get_data = False
> +    for item in line.split():
> +        if item == "MODINFO_START":
> +            get_kind = True
> +            continue
> +        if item.startswith("MODINFO_END"):
> +            get_data = False
> +            continue
> +        if get_kind:
> +            kind = item
> +            get_kind = False
> +            get_data = True
> +            continue
> +        if get_data:
> +            data += " " + item
> +            continue
> +    return (kind, data)
> +
> +def generate(name, lines):
> +    arch = ""
> +    objs = []
> +    deps = []
> +    opts = []
> +    for line in lines:
> +        if line.find("MODINFO_START") != -1:
> +            (kind, data) = parse_line(line)
> +            if kind == 'obj':
> +                objs.append(data)
> +            elif kind == 'dep':
> +                deps.append(data)
> +            elif kind == 'opts':
> +                opts.append(data)
> +            elif kind == 'arch':
> +                arch = data;
> +            else:
> +                print("unknown:", kind)
> +                exit(1)
> +
> +    print("    .name = \"%s\"," % name)
> +    if arch != "":
> +        print("    .arch = %s," % arch)
> +    print_array("objs", objs)
> +    print_array("deps", deps)
> +    print_array("opts", opts)
> +    print("},{");
> +
> +def print_pre():
> +    print("/* generated by scripts/modinfo.py */")

generated by scripts/modinfo-generate.py

> +    print("#include \"qemu/osdep.h\"")
> +    print("#include \"qemu/module.h\"")
> +    print("const QemuModinfo qemu_modinfo[] = {{")
> +
> +def print_post():
> +    print("    /* end of list */")
> +    print("}};")
> +
> +def main(args):
> +    print_pre()
> +    for modinfo in args:
> +        with open(modinfo) as f:
> +            lines = f.readlines()
> +        print("    /* %s */" % modinfo)
> +        (basename, ext) = os.path.splitext(modinfo)
> +        generate(basename, lines)
> +    print_post()
> +
> +if __name__ == "__main__":
> +    main(sys.argv[1:])
> diff --git a/include/qemu/module.h b/include/qemu/module.h
> index 81ef086da023..a98748d501d3 100644
> --- a/include/qemu/module.h
> +++ b/include/qemu/module.h
> @@ -98,4 +98,21 @@ void module_load_qom_all(void);
>  /* module registers QemuOpts <name> */
>  #define module_opts(name) modinfo(opts, name)
>  
> +/*
> + * module info database
> + *
> + * scripts/modinfo-generate.c will build this using the data collected
> + * by scripts/modinfo-collect.py
> + */
> +typedef struct QemuModinfo QemuModinfo;
> +struct QemuModinfo {
> +    const char *name;
> +    const char *arch;
> +    const char **objs;
> +    const char **deps;
> +    const char **opts;
> +};
> +extern const QemuModinfo qemu_modinfo[];
> +void module_init_info(const QemuModinfo *info);
> +
>  #endif
> diff --git a/softmmu/vl.c b/softmmu/vl.c
> index 326c1e908008..a4857ec43ff3 100644
> --- a/softmmu/vl.c
> +++ b/softmmu/vl.c
> @@ -2740,6 +2740,10 @@ void qemu_init(int argc, char **argv, char **envp)
>      error_init(argv[0]);
>      qemu_init_exec_dir(argv[0]);
>  
> +#ifdef CONFIG_MODULES
> +    module_init_info(qemu_modinfo);
> +#endif
> +
>      qemu_init_subsystems();
>  
>      /* first pass of option parsing */
> diff --git a/util/module.c b/util/module.c
> index eee8ff2de136..8d3e8275b9f7 100644
> --- a/util/module.c
> +++ b/util/module.c
> @@ -110,6 +110,17 @@ void module_call_init(module_init_type type)
>  }
>  
>  #ifdef CONFIG_MODULES
> +
> +static const QemuModinfo module_info_stub[] = { {
> +    /* end of list */
> +} };
> +static const QemuModinfo *module_info = module_info_stub;
> +
> +void module_init_info(const QemuModinfo *info)
> +{
> +    module_info = info;
> +}
> +
>  static int module_load_file(const char *fname, bool mayfail, bool export_symbols)
>  {
>      GModule *g_module;
> diff --git a/meson.build b/meson.build
> index bb99619257d5..9cf50a50d39a 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -2022,6 +2022,7 @@ subdir('tests/qtest/fuzz')
>  ########################
>  
>  modinfo_collect = find_program('scripts/modinfo-collect.py')
> +modinfo_generate = find_program('scripts/modinfo-generate.py')
>  modinfo_files = []
>  
>  block_mods = []
> @@ -2042,7 +2043,6 @@ foreach d, list : modules
>                                         output: d + '-' + m + '.modinfo',
>                                         input: module_ss.sources(),
>                                         capture: true,
> -                                       build_by_default: true, # to be removed when added to a target
>                                         command: [modinfo_collect, '@INPUT@'])
>        endif
>      else
> @@ -2055,6 +2055,17 @@ foreach d, list : modules
>    endforeach
>  endforeach
>  
> +if enable_modules
> +  modinfo_src = custom_target('modinfo.c',
> +                              output: 'modinfo.c',
> +                              input: modinfo_files,
> +                              command: [modinfo_generate, '@INPUT@'],
> +                              capture: true)
> +  modinfo_lib = static_library('modinfo', modinfo_src)
> +  modinfo_dep = declare_dependency(link_whole: modinfo_lib)
> +  softmmu_ss.add(modinfo_dep)
> +endif
> +
>  nm = find_program('nm')
>  undefsym = find_program('scripts/undefsym.py')
>  block_syms = custom_target('block.syms', output: 'block.syms',
> -- 
> 2.31.1
> 
>
Jose R. Ziviani June 22, 2021, 8:43 p.m. UTC | #2
On Fri, Jun 18, 2021 at 06:53:32AM +0200, Gerd Hoffmann wrote:
> Add script to generate C source with a small
> database containing the module meta-data.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  scripts/modinfo-generate.py | 84 +++++++++++++++++++++++++++++++++++++
>  include/qemu/module.h       | 17 ++++++++
>  softmmu/vl.c                |  4 ++
>  util/module.c               | 11 +++++
>  meson.build                 | 13 +++++-
>  5 files changed, 128 insertions(+), 1 deletion(-)
>  create mode 100755 scripts/modinfo-generate.py
> 
> diff --git a/scripts/modinfo-generate.py b/scripts/modinfo-generate.py
> new file mode 100755
> index 000000000000..2b925432655a
> --- /dev/null
> +++ b/scripts/modinfo-generate.py
> @@ -0,0 +1,84 @@
> +#!/usr/bin/env python3
> +# -*- coding: utf-8 -*-
> +
> +import os
> +import sys
> +
> +def print_array(name, values):
> +    if len(values) == 0:
> +        return
> +    list = ", ".join(values)
> +    print("    .%s = ((const char*[]){ %s, NULL })," % (name, list))
> +
> +def parse_line(line):
> +    kind = ""
> +    data = ""
> +    get_kind = False
> +    get_data = False
> +    for item in line.split():
> +        if item == "MODINFO_START":
> +            get_kind = True
> +            continue
> +        if item.startswith("MODINFO_END"):
> +            get_data = False
> +            continue
> +        if get_kind:
> +            kind = item
> +            get_kind = False
> +            get_data = True
> +            continue
> +        if get_data:
> +            data += " " + item
> +            continue
> +    return (kind, data)
> +
> +def generate(name, lines):
> +    arch = ""
> +    objs = []
> +    deps = []
> +    opts = []
> +    for line in lines:
> +        if line.find("MODINFO_START") != -1:
> +            (kind, data) = parse_line(line)
> +            if kind == 'obj':
> +                objs.append(data)
> +            elif kind == 'dep':
> +                deps.append(data)
> +            elif kind == 'opts':
> +                opts.append(data)
> +            elif kind == 'arch':
> +                arch = data;
> +            else:
> +                print("unknown:", kind)
> +                exit(1)
> +
> +    print("    .name = \"%s\"," % name)
> +    if arch != "":
> +        print("    .arch = %s," % arch)
> +    print_array("objs", objs)
> +    print_array("deps", deps)
> +    print_array("opts", opts)
> +    print("},{");
> +
> +def print_pre():
> +    print("/* generated by scripts/modinfo.py */")
> +    print("#include \"qemu/osdep.h\"")
> +    print("#include \"qemu/module.h\"")
> +    print("const QemuModinfo qemu_modinfo[] = {{")
> +
> +def print_post():
> +    print("    /* end of list */")
> +    print("}};")
> +
> +def main(args):
> +    print_pre()
> +    for modinfo in args:
> +        with open(modinfo) as f:
> +            lines = f.readlines()
> +        print("    /* %s */" % modinfo)
> +        (basename, ext) = os.path.splitext(modinfo)
> +        generate(basename, lines)
> +    print_post()

I attached a patch in this message to check if a dependency can be satisfied. It will detect the following case:
(in any module)
module_dep("blabla");

[2/5] Generating modinfo.c with a custom command (wrapped by meson to capture output)
FAILED: modinfo.c 
/usr/bin/meson --internal exe --capture modinfo.c -- /home/...
Dependency blabla cannot be satisfied
/* generated by scripts/modinfo.py */
#include "qemu/osdep.h"
#include "qemu/module.h"
const QemuModinfo qemu_modinfo[] = {{
    /* ui-curses.modinfo */
    .name = "ui-curses",
...
},{
    /* accel-tcg-x86_64.modinfo */
    .name = "accel-tcg-x86_64",
    .arch =  "x86_64",
    .objs = ((const char*[]){  ("tcg" "-" "accel" "-ops"), NULL }),
    .deps = ((const char*[]){  "blabla", NULL }),
},{
    /* end of list */
}};
ninja: build stopped: subcommand failed.
make: *** [Makefile:154: run-ninja] Error 1

It can help developers to know early they have a typo somewhere.
You can add this code if you like.

> +
> +if __name__ == "__main__":
> +    main(sys.argv[1:])
> diff --git a/include/qemu/module.h b/include/qemu/module.h
> index 81ef086da023..a98748d501d3 100644
> --- a/include/qemu/module.h
> +++ b/include/qemu/module.h
> @@ -98,4 +98,21 @@ void module_load_qom_all(void);
>  /* module registers QemuOpts <name> */
>  #define module_opts(name) modinfo(opts, name)
>  
> +/*
> + * module info database
> + *
> + * scripts/modinfo-generate.c will build this using the data collected
> + * by scripts/modinfo-collect.py
> + */
> +typedef struct QemuModinfo QemuModinfo;
> +struct QemuModinfo {
> +    const char *name;
> +    const char *arch;
> +    const char **objs;
> +    const char **deps;
> +    const char **opts;
> +};
> +extern const QemuModinfo qemu_modinfo[];
> +void module_init_info(const QemuModinfo *info);
> +
>  #endif
> diff --git a/softmmu/vl.c b/softmmu/vl.c
> index 326c1e908008..a4857ec43ff3 100644
> --- a/softmmu/vl.c
> +++ b/softmmu/vl.c
> @@ -2740,6 +2740,10 @@ void qemu_init(int argc, char **argv, char **envp)
>      error_init(argv[0]);
>      qemu_init_exec_dir(argv[0]);
>  
> +#ifdef CONFIG_MODULES
> +    module_init_info(qemu_modinfo);
> +#endif
> +
>      qemu_init_subsystems();
>  
>      /* first pass of option parsing */
> diff --git a/util/module.c b/util/module.c
> index eee8ff2de136..8d3e8275b9f7 100644
> --- a/util/module.c
> +++ b/util/module.c
> @@ -110,6 +110,17 @@ void module_call_init(module_init_type type)
>  }
>  
>  #ifdef CONFIG_MODULES
> +
> +static const QemuModinfo module_info_stub[] = { {
> +    /* end of list */
> +} };
> +static const QemuModinfo *module_info = module_info_stub;
> +
> +void module_init_info(const QemuModinfo *info)
> +{
> +    module_info = info;
> +}
> +
>  static int module_load_file(const char *fname, bool mayfail, bool export_symbols)
>  {
>      GModule *g_module;
> diff --git a/meson.build b/meson.build
> index bb99619257d5..9cf50a50d39a 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -2022,6 +2022,7 @@ subdir('tests/qtest/fuzz')
>  ########################
>  
>  modinfo_collect = find_program('scripts/modinfo-collect.py')
> +modinfo_generate = find_program('scripts/modinfo-generate.py')
>  modinfo_files = []
>  
>  block_mods = []
> @@ -2042,7 +2043,6 @@ foreach d, list : modules
>                                         output: d + '-' + m + '.modinfo',
>                                         input: module_ss.sources(),
>                                         capture: true,
> -                                       build_by_default: true, # to be removed when added to a target
>                                         command: [modinfo_collect, '@INPUT@'])
>        endif
>      else
> @@ -2055,6 +2055,17 @@ foreach d, list : modules
>    endforeach
>  endforeach
>  
> +if enable_modules
> +  modinfo_src = custom_target('modinfo.c',
> +                              output: 'modinfo.c',
> +                              input: modinfo_files,
> +                              command: [modinfo_generate, '@INPUT@'],
> +                              capture: true)
> +  modinfo_lib = static_library('modinfo', modinfo_src)
> +  modinfo_dep = declare_dependency(link_whole: modinfo_lib)
> +  softmmu_ss.add(modinfo_dep)
> +endif
> +
>  nm = find_program('nm')
>  undefsym = find_program('scripts/undefsym.py')
>  block_syms = custom_target('block.syms', output: 'block.syms',
> -- 
> 2.31.1
> 
>
diff mbox series

Patch

diff --git a/scripts/modinfo-generate.py b/scripts/modinfo-generate.py
new file mode 100755
index 000000000000..2b925432655a
--- /dev/null
+++ b/scripts/modinfo-generate.py
@@ -0,0 +1,84 @@ 
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+
+def print_array(name, values):
+    if len(values) == 0:
+        return
+    list = ", ".join(values)
+    print("    .%s = ((const char*[]){ %s, NULL })," % (name, list))
+
+def parse_line(line):
+    kind = ""
+    data = ""
+    get_kind = False
+    get_data = False
+    for item in line.split():
+        if item == "MODINFO_START":
+            get_kind = True
+            continue
+        if item.startswith("MODINFO_END"):
+            get_data = False
+            continue
+        if get_kind:
+            kind = item
+            get_kind = False
+            get_data = True
+            continue
+        if get_data:
+            data += " " + item
+            continue
+    return (kind, data)
+
+def generate(name, lines):
+    arch = ""
+    objs = []
+    deps = []
+    opts = []
+    for line in lines:
+        if line.find("MODINFO_START") != -1:
+            (kind, data) = parse_line(line)
+            if kind == 'obj':
+                objs.append(data)
+            elif kind == 'dep':
+                deps.append(data)
+            elif kind == 'opts':
+                opts.append(data)
+            elif kind == 'arch':
+                arch = data;
+            else:
+                print("unknown:", kind)
+                exit(1)
+
+    print("    .name = \"%s\"," % name)
+    if arch != "":
+        print("    .arch = %s," % arch)
+    print_array("objs", objs)
+    print_array("deps", deps)
+    print_array("opts", opts)
+    print("},{");
+
+def print_pre():
+    print("/* generated by scripts/modinfo.py */")
+    print("#include \"qemu/osdep.h\"")
+    print("#include \"qemu/module.h\"")
+    print("const QemuModinfo qemu_modinfo[] = {{")
+
+def print_post():
+    print("    /* end of list */")
+    print("}};")
+
+def main(args):
+    print_pre()
+    for modinfo in args:
+        with open(modinfo) as f:
+            lines = f.readlines()
+        print("    /* %s */" % modinfo)
+        (basename, ext) = os.path.splitext(modinfo)
+        generate(basename, lines)
+    print_post()
+
+if __name__ == "__main__":
+    main(sys.argv[1:])
diff --git a/include/qemu/module.h b/include/qemu/module.h
index 81ef086da023..a98748d501d3 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -98,4 +98,21 @@  void module_load_qom_all(void);
 /* module registers QemuOpts <name> */
 #define module_opts(name) modinfo(opts, name)
 
+/*
+ * module info database
+ *
+ * scripts/modinfo-generate.c will build this using the data collected
+ * by scripts/modinfo-collect.py
+ */
+typedef struct QemuModinfo QemuModinfo;
+struct QemuModinfo {
+    const char *name;
+    const char *arch;
+    const char **objs;
+    const char **deps;
+    const char **opts;
+};
+extern const QemuModinfo qemu_modinfo[];
+void module_init_info(const QemuModinfo *info);
+
 #endif
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 326c1e908008..a4857ec43ff3 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -2740,6 +2740,10 @@  void qemu_init(int argc, char **argv, char **envp)
     error_init(argv[0]);
     qemu_init_exec_dir(argv[0]);
 
+#ifdef CONFIG_MODULES
+    module_init_info(qemu_modinfo);
+#endif
+
     qemu_init_subsystems();
 
     /* first pass of option parsing */
diff --git a/util/module.c b/util/module.c
index eee8ff2de136..8d3e8275b9f7 100644
--- a/util/module.c
+++ b/util/module.c
@@ -110,6 +110,17 @@  void module_call_init(module_init_type type)
 }
 
 #ifdef CONFIG_MODULES
+
+static const QemuModinfo module_info_stub[] = { {
+    /* end of list */
+} };
+static const QemuModinfo *module_info = module_info_stub;
+
+void module_init_info(const QemuModinfo *info)
+{
+    module_info = info;
+}
+
 static int module_load_file(const char *fname, bool mayfail, bool export_symbols)
 {
     GModule *g_module;
diff --git a/meson.build b/meson.build
index bb99619257d5..9cf50a50d39a 100644
--- a/meson.build
+++ b/meson.build
@@ -2022,6 +2022,7 @@  subdir('tests/qtest/fuzz')
 ########################
 
 modinfo_collect = find_program('scripts/modinfo-collect.py')
+modinfo_generate = find_program('scripts/modinfo-generate.py')
 modinfo_files = []
 
 block_mods = []
@@ -2042,7 +2043,6 @@  foreach d, list : modules
                                        output: d + '-' + m + '.modinfo',
                                        input: module_ss.sources(),
                                        capture: true,
-                                       build_by_default: true, # to be removed when added to a target
                                        command: [modinfo_collect, '@INPUT@'])
       endif
     else
@@ -2055,6 +2055,17 @@  foreach d, list : modules
   endforeach
 endforeach
 
+if enable_modules
+  modinfo_src = custom_target('modinfo.c',
+                              output: 'modinfo.c',
+                              input: modinfo_files,
+                              command: [modinfo_generate, '@INPUT@'],
+                              capture: true)
+  modinfo_lib = static_library('modinfo', modinfo_src)
+  modinfo_dep = declare_dependency(link_whole: modinfo_lib)
+  softmmu_ss.add(modinfo_dep)
+endif
+
 nm = find_program('nm')
 undefsym = find_program('scripts/undefsym.py')
 block_syms = custom_target('block.syms', output: 'block.syms',