xref: /openbmc/qemu/scripts/meson-buildoptions.py (revision 604b70f6a4d072ddf7f00d3fdb5b977111fdeef1)
161d63097SPaolo Bonzini#! /usr/bin/env python3
261d63097SPaolo Bonzini
361d63097SPaolo Bonzini# Generate configure command line options handling code, based on Meson's
461d63097SPaolo Bonzini# user build options introspection data
561d63097SPaolo Bonzini#
661d63097SPaolo Bonzini# Copyright (C) 2021 Red Hat, Inc.
761d63097SPaolo Bonzini#
861d63097SPaolo Bonzini# Author: Paolo Bonzini <pbonzini@redhat.com>
961d63097SPaolo Bonzini#
1061d63097SPaolo Bonzini# This program is free software; you can redistribute it and/or modify
1161d63097SPaolo Bonzini# it under the terms of the GNU General Public License as published by
1261d63097SPaolo Bonzini# the Free Software Foundation; either version 2, or (at your option)
1361d63097SPaolo Bonzini# any later version.
1461d63097SPaolo Bonzini#
1561d63097SPaolo Bonzini# This program is distributed in the hope that it will be useful,
1661d63097SPaolo Bonzini# but WITHOUT ANY WARRANTY; without even the implied warranty of
1761d63097SPaolo Bonzini# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1861d63097SPaolo Bonzini# GNU General Public License for more details.
1961d63097SPaolo Bonzini#
2061d63097SPaolo Bonzini# You should have received a copy of the GNU General Public License
2161d63097SPaolo Bonzini# along with this program.  If not, see <https://www.gnu.org/licenses/>.
2261d63097SPaolo Bonzini
2361d63097SPaolo Bonziniimport json
2461d63097SPaolo Bonziniimport textwrap
2561d63097SPaolo Bonziniimport shlex
2661d63097SPaolo Bonziniimport sys
2761d63097SPaolo Bonzini
28*79fccf7eSPaolo Bonzini# Options with nonstandard names (e.g. --with/--without) or OS-dependent
29*79fccf7eSPaolo Bonzini# defaults.  Try not to add any.
303b4da132SPaolo BonziniSKIP_OPTIONS = {
313b4da132SPaolo Bonzini    "default_devices",
323b4da132SPaolo Bonzini    "fuzzing_engine",
333b4da132SPaolo Bonzini}
343b4da132SPaolo Bonzini
35*79fccf7eSPaolo Bonzini# Options whose name doesn't match the option for backwards compatibility
36*79fccf7eSPaolo Bonzini# reasons, because Meson gives them a funny name, or both
37119fc611SPaolo BonziniOPTION_NAMES = {
38c54b59eeSPaolo Bonzini    "b_coverage": "gcov",
39c54b59eeSPaolo Bonzini    "b_lto": "lto",
406739825aSPaolo Bonzini    "coroutine_backend": "with-coroutine",
41c0e705c6SPaolo Bonzini    "debug": "debug-info",
42119fc611SPaolo Bonzini    "malloc": "enable-malloc",
43b0b4323eSPaolo Bonzini    "pkgversion": "with-pkgversion",
44c09c1ce7SPaolo Bonzini    "qemu_firmwarepath": "firmwarepath",
45c36dd41bSPaolo Bonzini    "qemu_suffix": "with-suffix",
46119fc611SPaolo Bonzini    "trace_backends": "enable-trace-backends",
474fda6011SPaolo Bonzini    "trace_file": "with-trace-file",
48119fc611SPaolo Bonzini}
49119fc611SPaolo Bonzini
5039fb3cfcSPaolo Bonzini# Options that configure autodetects, even though meson defines them as boolean
5139fb3cfcSPaolo BonziniAUTO_OPTIONS = {
5239fb3cfcSPaolo Bonzini    "plugins",
53090a188cSPaolo Bonzini    "werror",
5439fb3cfcSPaolo Bonzini}
5539fb3cfcSPaolo Bonzini
56*79fccf7eSPaolo Bonzini# Builtin options that should be definable via configure.  Some of the others
57*79fccf7eSPaolo Bonzini# we really do not want (e.g. c_args is defined via the native file, not
58*79fccf7eSPaolo Bonzini# via -D, because it's a mix of CFLAGS and --extra-cflags); for specific
59*79fccf7eSPaolo Bonzini# cases "../configure -D" can be used as an escape hatch.
60a70248dbSPaolo BonziniBUILTIN_OPTIONS = {
61c54b59eeSPaolo Bonzini    "b_coverage",
62c54b59eeSPaolo Bonzini    "b_lto",
63c36dd41bSPaolo Bonzini    "bindir",
64c09c1ce7SPaolo Bonzini    "datadir",
65c0e705c6SPaolo Bonzini    "debug",
66c09c1ce7SPaolo Bonzini    "includedir",
67c09c1ce7SPaolo Bonzini    "libdir",
68c09c1ce7SPaolo Bonzini    "libexecdir",
69c09c1ce7SPaolo Bonzini    "localedir",
70c09c1ce7SPaolo Bonzini    "localstatedir",
71c09c1ce7SPaolo Bonzini    "mandir",
72c36dd41bSPaolo Bonzini    "prefix",
73a70248dbSPaolo Bonzini    "strip",
74c09c1ce7SPaolo Bonzini    "sysconfdir",
75090a188cSPaolo Bonzini    "werror",
76a70248dbSPaolo Bonzini}
77a70248dbSPaolo Bonzini
783b4da132SPaolo BonziniLINE_WIDTH = 76
793b4da132SPaolo Bonzini
803b4da132SPaolo Bonzini
813b4da132SPaolo Bonzini# Convert the default value of an option to the string used in
823b4da132SPaolo Bonzini# the help message
83808d15b3SPaolo Bonzinidef get_help(opt):
84808d15b3SPaolo Bonzini    if opt["name"] == "libdir":
85808d15b3SPaolo Bonzini        return 'system default'
86808d15b3SPaolo Bonzini    value = opt["value"]
873b4da132SPaolo Bonzini    if isinstance(value, list):
883b4da132SPaolo Bonzini        return ",".join(value)
893b4da132SPaolo Bonzini    if isinstance(value, bool):
903b4da132SPaolo Bonzini        return "enabled" if value else "disabled"
913b4da132SPaolo Bonzini    return str(value)
923b4da132SPaolo Bonzini
933b4da132SPaolo Bonzini
943b4da132SPaolo Bonzinidef wrap(left, text, indent):
953b4da132SPaolo Bonzini    spaces = " " * indent
963b4da132SPaolo Bonzini    if len(left) >= indent:
973b4da132SPaolo Bonzini        yield left
983b4da132SPaolo Bonzini        left = spaces
993b4da132SPaolo Bonzini    else:
1003b4da132SPaolo Bonzini        left = (left + spaces)[0:indent]
1013b4da132SPaolo Bonzini    yield from textwrap.wrap(
1023b4da132SPaolo Bonzini        text, width=LINE_WIDTH, initial_indent=left, subsequent_indent=spaces
1033b4da132SPaolo Bonzini    )
1043b4da132SPaolo Bonzini
1053b4da132SPaolo Bonzini
10661d63097SPaolo Bonzinidef sh_print(line=""):
10761d63097SPaolo Bonzini    print('  printf "%s\\n"', shlex.quote(line))
10861d63097SPaolo Bonzini
10961d63097SPaolo Bonzini
1103b4da132SPaolo Bonzinidef help_line(left, opt, indent, long):
1113b4da132SPaolo Bonzini    right = f'{opt["description"]}'
1123b4da132SPaolo Bonzini    if long:
113808d15b3SPaolo Bonzini        value = get_help(opt)
114119fc611SPaolo Bonzini        if value != "auto" and value != "":
1153b4da132SPaolo Bonzini            right += f" [{value}]"
1163b4da132SPaolo Bonzini    if "choices" in opt and long:
1173b4da132SPaolo Bonzini        choices = "/".join(sorted(opt["choices"]))
1183b4da132SPaolo Bonzini        right += f" (choices: {choices})"
1193b4da132SPaolo Bonzini    for x in wrap("  " + left, right, indent):
1203b4da132SPaolo Bonzini        sh_print(x)
1213b4da132SPaolo Bonzini
1223b4da132SPaolo Bonzini
1233b4da132SPaolo Bonzini# Return whether the option (a dictionary) can be used with
1243b4da132SPaolo Bonzini# arguments.  Booleans can never be used with arguments;
1253b4da132SPaolo Bonzini# combos allow an argument only if they accept other values
1263b4da132SPaolo Bonzini# than "auto", "enabled", and "disabled".
1273b4da132SPaolo Bonzinidef allow_arg(opt):
1283b4da132SPaolo Bonzini    if opt["type"] == "boolean":
1293b4da132SPaolo Bonzini        return False
1303b4da132SPaolo Bonzini    if opt["type"] != "combo":
1313b4da132SPaolo Bonzini        return True
1323b4da132SPaolo Bonzini    return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"})
1333b4da132SPaolo Bonzini
1343b4da132SPaolo Bonzini
135119fc611SPaolo Bonzini# Return whether the option (a dictionary) can be used without
136119fc611SPaolo Bonzini# arguments.  Booleans can only be used without arguments;
137119fc611SPaolo Bonzini# combos require an argument if they accept neither "enabled"
138119fc611SPaolo Bonzini# nor "disabled"
139119fc611SPaolo Bonzinidef require_arg(opt):
140119fc611SPaolo Bonzini    if opt["type"] == "boolean":
141119fc611SPaolo Bonzini        return False
142119fc611SPaolo Bonzini    if opt["type"] != "combo":
143119fc611SPaolo Bonzini        return True
144119fc611SPaolo Bonzini    return not ({"enabled", "disabled"}.intersection(opt["choices"]))
145119fc611SPaolo Bonzini
146119fc611SPaolo Bonzini
147a70248dbSPaolo Bonzinidef filter_options(json):
148a70248dbSPaolo Bonzini    if ":" in json["name"]:
149a70248dbSPaolo Bonzini        return False
150a70248dbSPaolo Bonzini    if json["section"] == "user":
151a70248dbSPaolo Bonzini        return json["name"] not in SKIP_OPTIONS
152a70248dbSPaolo Bonzini    else:
153a70248dbSPaolo Bonzini        return json["name"] in BUILTIN_OPTIONS
154a70248dbSPaolo Bonzini
155a70248dbSPaolo Bonzini
15661d63097SPaolo Bonzinidef load_options(json):
157a70248dbSPaolo Bonzini    json = [x for x in json if filter_options(x)]
15861d63097SPaolo Bonzini    return sorted(json, key=lambda x: x["name"])
15961d63097SPaolo Bonzini
16061d63097SPaolo Bonzini
161119fc611SPaolo Bonzinidef cli_option(opt):
162119fc611SPaolo Bonzini    name = opt["name"]
163119fc611SPaolo Bonzini    if name in OPTION_NAMES:
164119fc611SPaolo Bonzini        return OPTION_NAMES[name]
165119fc611SPaolo Bonzini    return name.replace("_", "-")
166119fc611SPaolo Bonzini
167119fc611SPaolo Bonzini
168119fc611SPaolo Bonzinidef cli_help_key(opt):
169119fc611SPaolo Bonzini    key = cli_option(opt)
170119fc611SPaolo Bonzini    if require_arg(opt):
171119fc611SPaolo Bonzini        return key
172119fc611SPaolo Bonzini    if opt["type"] == "boolean" and opt["value"]:
173119fc611SPaolo Bonzini        return f"disable-{key}"
174119fc611SPaolo Bonzini    return f"enable-{key}"
175119fc611SPaolo Bonzini
176119fc611SPaolo Bonzini
177119fc611SPaolo Bonzinidef cli_metavar(opt):
178119fc611SPaolo Bonzini    if opt["type"] == "string":
179119fc611SPaolo Bonzini        return "VALUE"
180119fc611SPaolo Bonzini    if opt["type"] == "array":
1818154f5e6SAkihiko Odaki        return "CHOICES" if "choices" in opt else "VALUES"
182119fc611SPaolo Bonzini    return "CHOICE"
183119fc611SPaolo Bonzini
184119fc611SPaolo Bonzini
18561d63097SPaolo Bonzinidef print_help(options):
18661d63097SPaolo Bonzini    print("meson_options_help() {")
18739fb3cfcSPaolo Bonzini    feature_opts = []
188119fc611SPaolo Bonzini    for opt in sorted(options, key=cli_help_key):
189119fc611SPaolo Bonzini        key = cli_help_key(opt)
1903b4da132SPaolo Bonzini        # The first section includes options that have an arguments,
1913b4da132SPaolo Bonzini        # and booleans (i.e., only one of enable/disable makes sense)
192119fc611SPaolo Bonzini        if require_arg(opt):
193119fc611SPaolo Bonzini            metavar = cli_metavar(opt)
194119fc611SPaolo Bonzini            left = f"--{key}={metavar}"
195119fc611SPaolo Bonzini            help_line(left, opt, 27, True)
19639fb3cfcSPaolo Bonzini        elif opt["type"] == "boolean" and opt["name"] not in AUTO_OPTIONS:
197119fc611SPaolo Bonzini            left = f"--{key}"
1983b4da132SPaolo Bonzini            help_line(left, opt, 27, False)
1993b4da132SPaolo Bonzini        elif allow_arg(opt):
2003b4da132SPaolo Bonzini            if opt["type"] == "combo" and "enabled" in opt["choices"]:
201119fc611SPaolo Bonzini                left = f"--{key}[=CHOICE]"
2023b4da132SPaolo Bonzini            else:
203119fc611SPaolo Bonzini                left = f"--{key}=CHOICE"
2043b4da132SPaolo Bonzini            help_line(left, opt, 27, True)
20539fb3cfcSPaolo Bonzini        else:
20639fb3cfcSPaolo Bonzini            feature_opts.append(opt)
2073b4da132SPaolo Bonzini
20861d63097SPaolo Bonzini    sh_print()
20961d63097SPaolo Bonzini    sh_print("Optional features, enabled with --enable-FEATURE and")
21061d63097SPaolo Bonzini    sh_print("disabled with --disable-FEATURE, default is enabled if available")
21161d63097SPaolo Bonzini    sh_print("(unless built with --without-default-features):")
21261d63097SPaolo Bonzini    sh_print()
21339fb3cfcSPaolo Bonzini    for opt in sorted(feature_opts, key=cli_option):
21439fb3cfcSPaolo Bonzini        key = cli_option(opt)
2153b4da132SPaolo Bonzini        help_line(key, opt, 18, False)
21661d63097SPaolo Bonzini    print("}")
21761d63097SPaolo Bonzini
21861d63097SPaolo Bonzini
21961d63097SPaolo Bonzinidef print_parse(options):
22061d63097SPaolo Bonzini    print("_meson_option_parse() {")
22161d63097SPaolo Bonzini    print("  case $1 in")
2223b4da132SPaolo Bonzini    for opt in options:
223119fc611SPaolo Bonzini        key = cli_option(opt)
2243b4da132SPaolo Bonzini        name = opt["name"]
225119fc611SPaolo Bonzini        if require_arg(opt):
2268154f5e6SAkihiko Odaki            if opt["type"] == "array" and not "choices" in opt:
2278154f5e6SAkihiko Odaki                print(f'    --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;')
2288154f5e6SAkihiko Odaki            else:
229119fc611SPaolo Bonzini                print(f'    --{key}=*) quote_sh "-D{name}=$2" ;;')
230119fc611SPaolo Bonzini        elif opt["type"] == "boolean":
2313b4da132SPaolo Bonzini            print(f'    --enable-{key}) printf "%s" -D{name}=true ;;')
2323b4da132SPaolo Bonzini            print(f'    --disable-{key}) printf "%s" -D{name}=false ;;')
2333b4da132SPaolo Bonzini        else:
2343b4da132SPaolo Bonzini            if opt["type"] == "combo" and "enabled" in opt["choices"]:
2353b4da132SPaolo Bonzini                print(f'    --enable-{key}) printf "%s" -D{name}=enabled ;;')
2363b4da132SPaolo Bonzini            if opt["type"] == "combo" and "disabled" in opt["choices"]:
2373b4da132SPaolo Bonzini                print(f'    --disable-{key}) printf "%s" -D{name}=disabled ;;')
2383b4da132SPaolo Bonzini            if allow_arg(opt):
2393b4da132SPaolo Bonzini                print(f'    --enable-{key}=*) quote_sh "-D{name}=$2" ;;')
24061d63097SPaolo Bonzini    print("    *) return 1 ;;")
24161d63097SPaolo Bonzini    print("  esac")
24261d63097SPaolo Bonzini    print("}")
24361d63097SPaolo Bonzini
24461d63097SPaolo Bonzini
24561d63097SPaolo Bonzinioptions = load_options(json.load(sys.stdin))
24661d63097SPaolo Bonziniprint("# This file is generated by meson-buildoptions.py, do not edit!")
24761d63097SPaolo Bonziniprint_help(options)
24861d63097SPaolo Bonziniprint_parse(options)
249