]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/meson-buildoptions.py
accel/tcg: Rename tcg_cpus_exec() -> tcg_cpu_exec()
[mirror_qemu.git] / scripts / meson-buildoptions.py
CommitLineData
61d63097
PB
1#! /usr/bin/env python3
2
3# Generate configure command line options handling code, based on Meson's
4# user build options introspection data
5#
6# Copyright (C) 2021 Red Hat, Inc.
7#
8# Author: Paolo Bonzini <pbonzini@redhat.com>
9#
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.
14#
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.
19#
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/>.
22
23import json
24import textwrap
25import shlex
26import sys
27
79fccf7e
PB
28# Options with nonstandard names (e.g. --with/--without) or OS-dependent
29# defaults. Try not to add any.
3b4da132 30SKIP_OPTIONS = {
3b4da132 31 "default_devices",
3b4da132 32 "fuzzing_engine",
3b4da132
PB
33}
34
79fccf7e
PB
35# Options whose name doesn't match the option for backwards compatibility
36# reasons, because Meson gives them a funny name, or both
119fc611 37OPTION_NAMES = {
c54b59ee
PB
38 "b_coverage": "gcov",
39 "b_lto": "lto",
6739825a 40 "coroutine_backend": "with-coroutine",
c0e705c6 41 "debug": "debug-info",
119fc611 42 "malloc": "enable-malloc",
b0b4323e 43 "pkgversion": "with-pkgversion",
c09c1ce7 44 "qemu_firmwarepath": "firmwarepath",
c36dd41b 45 "qemu_suffix": "with-suffix",
119fc611 46 "trace_backends": "enable-trace-backends",
4fda6011 47 "trace_file": "with-trace-file",
119fc611
PB
48}
49
39fb3cfc
PB
50# Options that configure autodetects, even though meson defines them as boolean
51AUTO_OPTIONS = {
52 "plugins",
090a188c 53 "werror",
39fb3cfc
PB
54}
55
79fccf7e
PB
56# Builtin options that should be definable via configure. Some of the others
57# we really do not want (e.g. c_args is defined via the native file, not
58# via -D, because it's a mix of CFLAGS and --extra-cflags); for specific
59# cases "../configure -D" can be used as an escape hatch.
a70248db 60BUILTIN_OPTIONS = {
c54b59ee
PB
61 "b_coverage",
62 "b_lto",
c36dd41b 63 "bindir",
c09c1ce7 64 "datadir",
c0e705c6 65 "debug",
c09c1ce7
PB
66 "includedir",
67 "libdir",
68 "libexecdir",
69 "localedir",
70 "localstatedir",
71 "mandir",
c36dd41b 72 "prefix",
a70248db 73 "strip",
c09c1ce7 74 "sysconfdir",
090a188c 75 "werror",
a70248db
PB
76}
77
3b4da132
PB
78LINE_WIDTH = 76
79
80
81# Convert the default value of an option to the string used in
82# the help message
808d15b3
PB
83def get_help(opt):
84 if opt["name"] == "libdir":
85 return 'system default'
86 value = opt["value"]
3b4da132
PB
87 if isinstance(value, list):
88 return ",".join(value)
89 if isinstance(value, bool):
90 return "enabled" if value else "disabled"
91 return str(value)
92
93
94def wrap(left, text, indent):
95 spaces = " " * indent
96 if len(left) >= indent:
97 yield left
98 left = spaces
99 else:
100 left = (left + spaces)[0:indent]
101 yield from textwrap.wrap(
102 text, width=LINE_WIDTH, initial_indent=left, subsequent_indent=spaces
103 )
104
105
61d63097
PB
106def sh_print(line=""):
107 print(' printf "%s\\n"', shlex.quote(line))
108
109
3b4da132
PB
110def help_line(left, opt, indent, long):
111 right = f'{opt["description"]}'
112 if long:
808d15b3 113 value = get_help(opt)
119fc611 114 if value != "auto" and value != "":
3b4da132
PB
115 right += f" [{value}]"
116 if "choices" in opt and long:
117 choices = "/".join(sorted(opt["choices"]))
118 right += f" (choices: {choices})"
119 for x in wrap(" " + left, right, indent):
120 sh_print(x)
121
122
123# Return whether the option (a dictionary) can be used with
124# arguments. Booleans can never be used with arguments;
125# combos allow an argument only if they accept other values
126# than "auto", "enabled", and "disabled".
127def allow_arg(opt):
128 if opt["type"] == "boolean":
129 return False
130 if opt["type"] != "combo":
131 return True
132 return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"})
133
134
119fc611
PB
135# Return whether the option (a dictionary) can be used without
136# arguments. Booleans can only be used without arguments;
137# combos require an argument if they accept neither "enabled"
138# nor "disabled"
139def require_arg(opt):
140 if opt["type"] == "boolean":
141 return False
142 if opt["type"] != "combo":
143 return True
144 return not ({"enabled", "disabled"}.intersection(opt["choices"]))
145
146
a70248db
PB
147def filter_options(json):
148 if ":" in json["name"]:
149 return False
150 if json["section"] == "user":
151 return json["name"] not in SKIP_OPTIONS
152 else:
153 return json["name"] in BUILTIN_OPTIONS
154
155
61d63097 156def load_options(json):
a70248db 157 json = [x for x in json if filter_options(x)]
61d63097
PB
158 return sorted(json, key=lambda x: x["name"])
159
160
119fc611
PB
161def cli_option(opt):
162 name = opt["name"]
163 if name in OPTION_NAMES:
164 return OPTION_NAMES[name]
165 return name.replace("_", "-")
166
167
168def cli_help_key(opt):
169 key = cli_option(opt)
170 if require_arg(opt):
171 return key
172 if opt["type"] == "boolean" and opt["value"]:
173 return f"disable-{key}"
174 return f"enable-{key}"
175
176
177def cli_metavar(opt):
178 if opt["type"] == "string":
179 return "VALUE"
180 if opt["type"] == "array":
8154f5e6 181 return "CHOICES" if "choices" in opt else "VALUES"
119fc611
PB
182 return "CHOICE"
183
184
61d63097
PB
185def print_help(options):
186 print("meson_options_help() {")
39fb3cfc 187 feature_opts = []
119fc611
PB
188 for opt in sorted(options, key=cli_help_key):
189 key = cli_help_key(opt)
3b4da132
PB
190 # The first section includes options that have an arguments,
191 # and booleans (i.e., only one of enable/disable makes sense)
119fc611
PB
192 if require_arg(opt):
193 metavar = cli_metavar(opt)
194 left = f"--{key}={metavar}"
195 help_line(left, opt, 27, True)
39fb3cfc 196 elif opt["type"] == "boolean" and opt["name"] not in AUTO_OPTIONS:
119fc611 197 left = f"--{key}"
3b4da132
PB
198 help_line(left, opt, 27, False)
199 elif allow_arg(opt):
200 if opt["type"] == "combo" and "enabled" in opt["choices"]:
119fc611 201 left = f"--{key}[=CHOICE]"
3b4da132 202 else:
119fc611 203 left = f"--{key}=CHOICE"
3b4da132 204 help_line(left, opt, 27, True)
39fb3cfc
PB
205 else:
206 feature_opts.append(opt)
3b4da132 207
61d63097
PB
208 sh_print()
209 sh_print("Optional features, enabled with --enable-FEATURE and")
210 sh_print("disabled with --disable-FEATURE, default is enabled if available")
211 sh_print("(unless built with --without-default-features):")
212 sh_print()
39fb3cfc
PB
213 for opt in sorted(feature_opts, key=cli_option):
214 key = cli_option(opt)
215 help_line(key, opt, 18, False)
61d63097
PB
216 print("}")
217
218
219def print_parse(options):
220 print("_meson_option_parse() {")
221 print(" case $1 in")
3b4da132 222 for opt in options:
119fc611 223 key = cli_option(opt)
3b4da132 224 name = opt["name"]
119fc611 225 if require_arg(opt):
8154f5e6
AO
226 if opt["type"] == "array" and not "choices" in opt:
227 print(f' --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;')
228 else:
229 print(f' --{key}=*) quote_sh "-D{name}=$2" ;;')
119fc611 230 elif opt["type"] == "boolean":
3b4da132
PB
231 print(f' --enable-{key}) printf "%s" -D{name}=true ;;')
232 print(f' --disable-{key}) printf "%s" -D{name}=false ;;')
233 else:
234 if opt["type"] == "combo" and "enabled" in opt["choices"]:
235 print(f' --enable-{key}) printf "%s" -D{name}=enabled ;;')
236 if opt["type"] == "combo" and "disabled" in opt["choices"]:
237 print(f' --disable-{key}) printf "%s" -D{name}=disabled ;;')
238 if allow_arg(opt):
239 print(f' --enable-{key}=*) quote_sh "-D{name}=$2" ;;')
61d63097
PB
240 print(" *) return 1 ;;")
241 print(" esac")
242 print("}")
243
244
245options = load_options(json.load(sys.stdin))
246print("# This file is generated by meson-buildoptions.py, do not edit!")
247print_help(options)
248print_parse(options)