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