| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  | #! /usr/bin/env python3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Generate configure command line options handling code, based on Meson's | 
					
						
							|  |  |  | # user build options introspection data | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Copyright (C) 2021 Red Hat, Inc. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Author: Paolo Bonzini <pbonzini@redhat.com> | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  | # it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | # the Free Software Foundation; either version 2, or (at your option) | 
					
						
							|  |  |  | # any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | # GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program.  If not, see <https://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | import textwrap | 
					
						
							|  |  |  | import shlex | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 11:20:01 +02:00
										 |  |  | # Options with nonstandard names (e.g. --with/--without) or OS-dependent | 
					
						
							|  |  |  | # defaults.  Try not to add any. | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  | SKIP_OPTIONS = { | 
					
						
							|  |  |  |     "default_devices", | 
					
						
							|  |  |  |     "fuzzing_engine", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 11:20:01 +02:00
										 |  |  | # Options whose name doesn't match the option for backwards compatibility | 
					
						
							|  |  |  | # reasons, because Meson gives them a funny name, or both | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  | OPTION_NAMES = { | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:58 +02:00
										 |  |  |     "b_coverage": "gcov", | 
					
						
							|  |  |  |     "b_lto": "lto", | 
					
						
							| 
									
										
										
										
											2022-10-12 13:19:35 +02:00
										 |  |  |     "coroutine_backend": "with-coroutine", | 
					
						
							| 
									
										
										
										
											2023-05-11 09:38:53 +02:00
										 |  |  |     "debug": "debug-info", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |     "malloc": "enable-malloc", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:54 +02:00
										 |  |  |     "pkgversion": "with-pkgversion", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:57 +02:00
										 |  |  |     "qemu_firmwarepath": "firmwarepath", | 
					
						
							| 
									
										
										
										
											2023-10-16 08:18:08 +02:00
										 |  |  |     "qemu_suffix": "with-suffix", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |     "trace_backends": "enable-trace-backends", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:51 +02:00
										 |  |  |     "trace_file": "with-trace-file", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-18 11:06:48 +02:00
										 |  |  | # Options that configure autodetects, even though meson defines them as boolean | 
					
						
							|  |  |  | AUTO_OPTIONS = { | 
					
						
							|  |  |  |     "plugins", | 
					
						
							| 
									
										
										
										
											2023-10-16 08:20:13 +02:00
										 |  |  |     "werror", | 
					
						
							| 
									
										
										
										
											2023-09-18 11:06:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 11:20:01 +02:00
										 |  |  | # Builtin options that should be definable via configure.  Some of the others | 
					
						
							|  |  |  | # we really do not want (e.g. c_args is defined via the native file, not | 
					
						
							|  |  |  | # via -D, because it's a mix of CFLAGS and --extra-cflags); for specific | 
					
						
							|  |  |  | # cases "../configure -D" can be used as an escape hatch. | 
					
						
							| 
									
										
										
										
											2021-11-09 10:36:39 +01:00
										 |  |  | BUILTIN_OPTIONS = { | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:58 +02:00
										 |  |  |     "b_coverage", | 
					
						
							|  |  |  |     "b_lto", | 
					
						
							| 
									
										
										
										
											2023-10-16 08:18:08 +02:00
										 |  |  |     "bindir", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:57 +02:00
										 |  |  |     "datadir", | 
					
						
							| 
									
										
										
										
											2023-05-11 09:38:53 +02:00
										 |  |  |     "debug", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:57 +02:00
										 |  |  |     "includedir", | 
					
						
							|  |  |  |     "libdir", | 
					
						
							|  |  |  |     "libexecdir", | 
					
						
							|  |  |  |     "localedir", | 
					
						
							|  |  |  |     "localstatedir", | 
					
						
							|  |  |  |     "mandir", | 
					
						
							| 
									
										
										
										
											2023-10-16 08:18:08 +02:00
										 |  |  |     "prefix", | 
					
						
							| 
									
										
										
										
											2021-11-09 10:36:39 +01:00
										 |  |  |     "strip", | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:57 +02:00
										 |  |  |     "sysconfdir", | 
					
						
							| 
									
										
										
										
											2023-10-16 08:20:13 +02:00
										 |  |  |     "werror", | 
					
						
							| 
									
										
										
										
											2021-11-09 10:36:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  | LINE_WIDTH = 76 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Convert the default value of an option to the string used in | 
					
						
							|  |  |  | # the help message | 
					
						
							| 
									
										
										
										
											2023-02-06 13:32:32 +01:00
										 |  |  | def get_help(opt): | 
					
						
							|  |  |  |     if opt["name"] == "libdir": | 
					
						
							|  |  |  |         return 'system default' | 
					
						
							|  |  |  |     value = opt["value"] | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |     if isinstance(value, list): | 
					
						
							|  |  |  |         return ",".join(value) | 
					
						
							|  |  |  |     if isinstance(value, bool): | 
					
						
							|  |  |  |         return "enabled" if value else "disabled" | 
					
						
							|  |  |  |     return str(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def wrap(left, text, indent): | 
					
						
							|  |  |  |     spaces = " " * indent | 
					
						
							|  |  |  |     if len(left) >= indent: | 
					
						
							|  |  |  |         yield left | 
					
						
							|  |  |  |         left = spaces | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         left = (left + spaces)[0:indent] | 
					
						
							|  |  |  |     yield from textwrap.wrap( | 
					
						
							|  |  |  |         text, width=LINE_WIDTH, initial_indent=left, subsequent_indent=spaces | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  | def sh_print(line=""): | 
					
						
							|  |  |  |     print('  printf "%s\\n"', shlex.quote(line)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  | def help_line(left, opt, indent, long): | 
					
						
							|  |  |  |     right = f'{opt["description"]}' | 
					
						
							|  |  |  |     if long: | 
					
						
							| 
									
										
										
										
											2023-02-06 13:32:32 +01:00
										 |  |  |         value = get_help(opt) | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |         if value != "auto" and value != "": | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |             right += f" [{value}]" | 
					
						
							|  |  |  |     if "choices" in opt and long: | 
					
						
							|  |  |  |         choices = "/".join(sorted(opt["choices"])) | 
					
						
							|  |  |  |         right += f" (choices: {choices})" | 
					
						
							|  |  |  |     for x in wrap("  " + left, right, indent): | 
					
						
							|  |  |  |         sh_print(x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Return whether the option (a dictionary) can be used with | 
					
						
							|  |  |  | # arguments.  Booleans can never be used with arguments; | 
					
						
							|  |  |  | # combos allow an argument only if they accept other values | 
					
						
							|  |  |  | # than "auto", "enabled", and "disabled". | 
					
						
							|  |  |  | def allow_arg(opt): | 
					
						
							|  |  |  |     if opt["type"] == "boolean": | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if opt["type"] != "combo": | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  | # Return whether the option (a dictionary) can be used without | 
					
						
							|  |  |  | # arguments.  Booleans can only be used without arguments; | 
					
						
							|  |  |  | # combos require an argument if they accept neither "enabled" | 
					
						
							|  |  |  | # nor "disabled" | 
					
						
							|  |  |  | def require_arg(opt): | 
					
						
							|  |  |  |     if opt["type"] == "boolean": | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if opt["type"] != "combo": | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     return not ({"enabled", "disabled"}.intersection(opt["choices"])) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-09 10:36:39 +01:00
										 |  |  | def filter_options(json): | 
					
						
							|  |  |  |     if ":" in json["name"]: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if json["section"] == "user": | 
					
						
							|  |  |  |         return json["name"] not in SKIP_OPTIONS | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return json["name"] in BUILTIN_OPTIONS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  | def load_options(json): | 
					
						
							| 
									
										
										
										
											2021-11-09 10:36:39 +01:00
										 |  |  |     json = [x for x in json if filter_options(x)] | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  |     return sorted(json, key=lambda x: x["name"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  | def cli_option(opt): | 
					
						
							|  |  |  |     name = opt["name"] | 
					
						
							|  |  |  |     if name in OPTION_NAMES: | 
					
						
							|  |  |  |         return OPTION_NAMES[name] | 
					
						
							|  |  |  |     return name.replace("_", "-") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def cli_help_key(opt): | 
					
						
							|  |  |  |     key = cli_option(opt) | 
					
						
							|  |  |  |     if require_arg(opt): | 
					
						
							|  |  |  |         return key | 
					
						
							|  |  |  |     if opt["type"] == "boolean" and opt["value"]: | 
					
						
							|  |  |  |         return f"disable-{key}" | 
					
						
							|  |  |  |     return f"enable-{key}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def cli_metavar(opt): | 
					
						
							|  |  |  |     if opt["type"] == "string": | 
					
						
							|  |  |  |         return "VALUE" | 
					
						
							|  |  |  |     if opt["type"] == "array": | 
					
						
							| 
									
										
										
										
											2022-06-25 00:40:42 +09:00
										 |  |  |         return "CHOICES" if "choices" in opt else "VALUES" | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |     return "CHOICE" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  | def print_help(options): | 
					
						
							|  |  |  |     print("meson_options_help() {") | 
					
						
							| 
									
										
										
										
											2023-09-18 11:06:48 +02:00
										 |  |  |     feature_opts = [] | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |     for opt in sorted(options, key=cli_help_key): | 
					
						
							|  |  |  |         key = cli_help_key(opt) | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |         # The first section includes options that have an arguments, | 
					
						
							|  |  |  |         # and booleans (i.e., only one of enable/disable makes sense) | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |         if require_arg(opt): | 
					
						
							|  |  |  |             metavar = cli_metavar(opt) | 
					
						
							|  |  |  |             left = f"--{key}={metavar}" | 
					
						
							|  |  |  |             help_line(left, opt, 27, True) | 
					
						
							| 
									
										
										
										
											2023-09-18 11:06:48 +02:00
										 |  |  |         elif opt["type"] == "boolean" and opt["name"] not in AUTO_OPTIONS: | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |             left = f"--{key}" | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |             help_line(left, opt, 27, False) | 
					
						
							|  |  |  |         elif allow_arg(opt): | 
					
						
							|  |  |  |             if opt["type"] == "combo" and "enabled" in opt["choices"]: | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |                 left = f"--{key}[=CHOICE]" | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |                 left = f"--{key}=CHOICE" | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |             help_line(left, opt, 27, True) | 
					
						
							| 
									
										
										
										
											2023-09-18 11:06:48 +02:00
										 |  |  |         else: | 
					
						
							|  |  |  |             feature_opts.append(opt) | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  |     sh_print() | 
					
						
							|  |  |  |     sh_print("Optional features, enabled with --enable-FEATURE and") | 
					
						
							|  |  |  |     sh_print("disabled with --disable-FEATURE, default is enabled if available") | 
					
						
							|  |  |  |     sh_print("(unless built with --without-default-features):") | 
					
						
							|  |  |  |     sh_print() | 
					
						
							| 
									
										
										
										
											2023-09-18 11:06:48 +02:00
										 |  |  |     for opt in sorted(feature_opts, key=cli_option): | 
					
						
							|  |  |  |         key = cli_option(opt) | 
					
						
							|  |  |  |         help_line(key, opt, 18, False) | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  |     print("}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def print_parse(options): | 
					
						
							|  |  |  |     print("_meson_option_parse() {") | 
					
						
							|  |  |  |     print("  case $1 in") | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |     for opt in options: | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |         key = cli_option(opt) | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |         name = opt["name"] | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |         if require_arg(opt): | 
					
						
							| 
									
										
										
										
											2022-06-25 00:40:42 +09:00
										 |  |  |             if opt["type"] == "array" and not "choices" in opt: | 
					
						
							|  |  |  |                 print(f'    --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;') | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 print(f'    --{key}=*) quote_sh "-D{name}=$2" ;;') | 
					
						
							| 
									
										
										
										
											2022-04-20 17:33:48 +02:00
										 |  |  |         elif opt["type"] == "boolean": | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:29 +02:00
										 |  |  |             print(f'    --enable-{key}) printf "%s" -D{name}=true ;;') | 
					
						
							|  |  |  |             print(f'    --disable-{key}) printf "%s" -D{name}=false ;;') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if opt["type"] == "combo" and "enabled" in opt["choices"]: | 
					
						
							|  |  |  |                 print(f'    --enable-{key}) printf "%s" -D{name}=enabled ;;') | 
					
						
							|  |  |  |             if opt["type"] == "combo" and "disabled" in opt["choices"]: | 
					
						
							|  |  |  |                 print(f'    --disable-{key}) printf "%s" -D{name}=disabled ;;') | 
					
						
							|  |  |  |             if allow_arg(opt): | 
					
						
							|  |  |  |                 print(f'    --enable-{key}=*) quote_sh "-D{name}=$2" ;;') | 
					
						
							| 
									
										
										
										
											2021-10-07 15:08:28 +02:00
										 |  |  |     print("    *) return 1 ;;") | 
					
						
							|  |  |  |     print("  esac") | 
					
						
							|  |  |  |     print("}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | options = load_options(json.load(sys.stdin)) | 
					
						
							|  |  |  | print("# This file is generated by meson-buildoptions.py, do not edit!") | 
					
						
							|  |  |  | print_help(options) | 
					
						
							|  |  |  | print_parse(options) |