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 28SKIP_OPTIONS = { 29 "audio_drv_list", 30 "default_devices", 31 "docdir", 32 "fuzzing_engine", 33 "qemu_firmwarepath", 34 "qemu_suffix", 35 "sphinx_build", 36 "trace_file", 37} 38 39LINE_WIDTH = 76 40 41 42# Convert the default value of an option to the string used in 43# the help message 44def value_to_help(value): 45 if isinstance(value, list): 46 return ",".join(value) 47 if isinstance(value, bool): 48 return "enabled" if value else "disabled" 49 return str(value) 50 51 52def wrap(left, text, indent): 53 spaces = " " * indent 54 if len(left) >= indent: 55 yield left 56 left = spaces 57 else: 58 left = (left + spaces)[0:indent] 59 yield from textwrap.wrap( 60 text, width=LINE_WIDTH, initial_indent=left, subsequent_indent=spaces 61 ) 62 63 64def sh_print(line=""): 65 print(' printf "%s\\n"', shlex.quote(line)) 66 67 68def help_line(left, opt, indent, long): 69 right = f'{opt["description"]}' 70 if long: 71 value = value_to_help(opt["value"]) 72 if value != "auto": 73 right += f" [{value}]" 74 if "choices" in opt and long: 75 choices = "/".join(sorted(opt["choices"])) 76 right += f" (choices: {choices})" 77 for x in wrap(" " + left, right, indent): 78 sh_print(x) 79 80 81# Return whether the option (a dictionary) can be used with 82# arguments. Booleans can never be used with arguments; 83# combos allow an argument only if they accept other values 84# than "auto", "enabled", and "disabled". 85def allow_arg(opt): 86 if opt["type"] == "boolean": 87 return False 88 if opt["type"] != "combo": 89 return True 90 return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"}) 91 92 93def load_options(json): 94 json = [ 95 x 96 for x in json 97 if x["section"] == "user" 98 and ":" not in x["name"] 99 and x["name"] not in SKIP_OPTIONS 100 ] 101 return sorted(json, key=lambda x: x["name"]) 102 103 104def print_help(options): 105 print("meson_options_help() {") 106 for opt in options: 107 key = opt["name"].replace("_", "-") 108 # The first section includes options that have an arguments, 109 # and booleans (i.e., only one of enable/disable makes sense) 110 if opt["type"] == "boolean": 111 left = f"--disable-{key}" if opt["value"] else f"--enable-{key}" 112 help_line(left, opt, 27, False) 113 elif allow_arg(opt): 114 if opt["type"] == "combo" and "enabled" in opt["choices"]: 115 left = f"--enable-{key}[=CHOICE]" 116 else: 117 left = f"--enable-{key}=CHOICE" 118 help_line(left, opt, 27, True) 119 120 sh_print() 121 sh_print("Optional features, enabled with --enable-FEATURE and") 122 sh_print("disabled with --disable-FEATURE, default is enabled if available") 123 sh_print("(unless built with --without-default-features):") 124 sh_print() 125 for opt in options: 126 key = opt["name"].replace("_", "-") 127 if opt["type"] != "boolean" and not allow_arg(opt): 128 help_line(key, opt, 18, False) 129 print("}") 130 131 132def print_parse(options): 133 print("_meson_option_parse() {") 134 print(" case $1 in") 135 for opt in options: 136 key = opt["name"].replace("_", "-") 137 name = opt["name"] 138 if opt["type"] == "boolean": 139 print(f' --enable-{key}) printf "%s" -D{name}=true ;;') 140 print(f' --disable-{key}) printf "%s" -D{name}=false ;;') 141 else: 142 if opt["type"] == "combo" and "enabled" in opt["choices"]: 143 print(f' --enable-{key}) printf "%s" -D{name}=enabled ;;') 144 if opt["type"] == "combo" and "disabled" in opt["choices"]: 145 print(f' --disable-{key}) printf "%s" -D{name}=disabled ;;') 146 if allow_arg(opt): 147 print(f' --enable-{key}=*) quote_sh "-D{name}=$2" ;;') 148 print(" *) return 1 ;;") 149 print(" esac") 150 print("}") 151 152 153def fixup_options(options): 154 # Meson <= 0.60 does not include the choices in array options, fix that up 155 for opt in options: 156 if opt["name"] == "trace_backends": 157 opt["choices"] = [ 158 "dtrace", 159 "ftrace", 160 "log", 161 "nop", 162 "simple", 163 "syslog", 164 "ust", 165 ] 166 167 168options = load_options(json.load(sys.stdin)) 169fixup_options(options) 170print("# This file is generated by meson-buildoptions.py, do not edit!") 171print_help(options) 172print_parse(options) 173