configure: clean up plugin option handling
[qemu/ar7.git] / scripts / meson-buildoptions.py
blobb787c84e914fbbb9614188f999cfbe42f343347c
1 #! /usr/bin/env python3
3 # Generate configure command line options handling code, based on Meson's
4 # user build options introspection data
6 # Copyright (C) 2021 Red Hat, Inc.
8 # Author: Paolo Bonzini <pbonzini@redhat.com>
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2, or (at your option)
13 # any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program. If not, see <https://www.gnu.org/licenses/>.
23 import json
24 import textwrap
25 import shlex
26 import sys
28 SKIP_OPTIONS = {
29 "default_devices",
30 "fuzzing_engine",
31 "qemu_suffix",
32 "smbd",
35 OPTION_NAMES = {
36 "b_coverage": "gcov",
37 "b_lto": "lto",
38 "coroutine_backend": "with-coroutine",
39 "debug": "debug-info",
40 "malloc": "enable-malloc",
41 "pkgversion": "with-pkgversion",
42 "qemu_firmwarepath": "firmwarepath",
43 "trace_backends": "enable-trace-backends",
44 "trace_file": "with-trace-file",
47 # Options that configure autodetects, even though meson defines them as boolean
48 AUTO_OPTIONS = {
49 "plugins",
52 BUILTIN_OPTIONS = {
53 "b_coverage",
54 "b_lto",
55 "datadir",
56 "debug",
57 "includedir",
58 "libdir",
59 "libexecdir",
60 "localedir",
61 "localstatedir",
62 "mandir",
63 "strip",
64 "sysconfdir",
67 LINE_WIDTH = 76
70 # Convert the default value of an option to the string used in
71 # the help message
72 def get_help(opt):
73 if opt["name"] == "libdir":
74 return 'system default'
75 value = opt["value"]
76 if isinstance(value, list):
77 return ",".join(value)
78 if isinstance(value, bool):
79 return "enabled" if value else "disabled"
80 return str(value)
83 def wrap(left, text, indent):
84 spaces = " " * indent
85 if len(left) >= indent:
86 yield left
87 left = spaces
88 else:
89 left = (left + spaces)[0:indent]
90 yield from textwrap.wrap(
91 text, width=LINE_WIDTH, initial_indent=left, subsequent_indent=spaces
95 def sh_print(line=""):
96 print(' printf "%s\\n"', shlex.quote(line))
99 def help_line(left, opt, indent, long):
100 right = f'{opt["description"]}'
101 if long:
102 value = get_help(opt)
103 if value != "auto" and value != "":
104 right += f" [{value}]"
105 if "choices" in opt and long:
106 choices = "/".join(sorted(opt["choices"]))
107 right += f" (choices: {choices})"
108 for x in wrap(" " + left, right, indent):
109 sh_print(x)
112 # Return whether the option (a dictionary) can be used with
113 # arguments. Booleans can never be used with arguments;
114 # combos allow an argument only if they accept other values
115 # than "auto", "enabled", and "disabled".
116 def allow_arg(opt):
117 if opt["type"] == "boolean":
118 return False
119 if opt["type"] != "combo":
120 return True
121 return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"})
124 # Return whether the option (a dictionary) can be used without
125 # arguments. Booleans can only be used without arguments;
126 # combos require an argument if they accept neither "enabled"
127 # nor "disabled"
128 def require_arg(opt):
129 if opt["type"] == "boolean":
130 return False
131 if opt["type"] != "combo":
132 return True
133 return not ({"enabled", "disabled"}.intersection(opt["choices"]))
136 def filter_options(json):
137 if ":" in json["name"]:
138 return False
139 if json["section"] == "user":
140 return json["name"] not in SKIP_OPTIONS
141 else:
142 return json["name"] in BUILTIN_OPTIONS
145 def load_options(json):
146 json = [x for x in json if filter_options(x)]
147 return sorted(json, key=lambda x: x["name"])
150 def cli_option(opt):
151 name = opt["name"]
152 if name in OPTION_NAMES:
153 return OPTION_NAMES[name]
154 return name.replace("_", "-")
157 def cli_help_key(opt):
158 key = cli_option(opt)
159 if require_arg(opt):
160 return key
161 if opt["type"] == "boolean" and opt["value"]:
162 return f"disable-{key}"
163 return f"enable-{key}"
166 def cli_metavar(opt):
167 if opt["type"] == "string":
168 return "VALUE"
169 if opt["type"] == "array":
170 return "CHOICES" if "choices" in opt else "VALUES"
171 return "CHOICE"
174 def print_help(options):
175 print("meson_options_help() {")
176 feature_opts = []
177 for opt in sorted(options, key=cli_help_key):
178 key = cli_help_key(opt)
179 # The first section includes options that have an arguments,
180 # and booleans (i.e., only one of enable/disable makes sense)
181 if require_arg(opt):
182 metavar = cli_metavar(opt)
183 left = f"--{key}={metavar}"
184 help_line(left, opt, 27, True)
185 elif opt["type"] == "boolean" and opt["name"] not in AUTO_OPTIONS:
186 left = f"--{key}"
187 help_line(left, opt, 27, False)
188 elif allow_arg(opt):
189 if opt["type"] == "combo" and "enabled" in opt["choices"]:
190 left = f"--{key}[=CHOICE]"
191 else:
192 left = f"--{key}=CHOICE"
193 help_line(left, opt, 27, True)
194 else:
195 feature_opts.append(opt)
197 sh_print()
198 sh_print("Optional features, enabled with --enable-FEATURE and")
199 sh_print("disabled with --disable-FEATURE, default is enabled if available")
200 sh_print("(unless built with --without-default-features):")
201 sh_print()
202 for opt in sorted(feature_opts, key=cli_option):
203 key = cli_option(opt)
204 help_line(key, opt, 18, False)
205 print("}")
208 def print_parse(options):
209 print("_meson_option_parse() {")
210 print(" case $1 in")
211 for opt in options:
212 key = cli_option(opt)
213 name = opt["name"]
214 if require_arg(opt):
215 if opt["type"] == "array" and not "choices" in opt:
216 print(f' --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;')
217 else:
218 print(f' --{key}=*) quote_sh "-D{name}=$2" ;;')
219 elif opt["type"] == "boolean":
220 print(f' --enable-{key}) printf "%s" -D{name}=true ;;')
221 print(f' --disable-{key}) printf "%s" -D{name}=false ;;')
222 else:
223 if opt["type"] == "combo" and "enabled" in opt["choices"]:
224 print(f' --enable-{key}) printf "%s" -D{name}=enabled ;;')
225 if opt["type"] == "combo" and "disabled" in opt["choices"]:
226 print(f' --disable-{key}) printf "%s" -D{name}=disabled ;;')
227 if allow_arg(opt):
228 print(f' --enable-{key}=*) quote_sh "-D{name}=$2" ;;')
229 print(" *) return 1 ;;")
230 print(" esac")
231 print("}")
234 options = load_options(json.load(sys.stdin))
235 print("# This file is generated by meson-buildoptions.py, do not edit!")
236 print_help(options)
237 print_parse(options)