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