]>
Commit | Line | Data |
---|---|---|
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 | ||
23 | import json | |
24 | import textwrap | |
25 | import shlex | |
26 | import sys | |
27 | ||
3b4da132 | 28 | SKIP_OPTIONS = { |
3b4da132 | 29 | "default_devices", |
3b4da132 | 30 | "fuzzing_engine", |
3b4da132 | 31 | "qemu_suffix", |
35acbb30 | 32 | "smbd", |
3b4da132 PB |
33 | } |
34 | ||
119fc611 | 35 | OPTION_NAMES = { |
c54b59ee PB |
36 | "b_coverage": "gcov", |
37 | "b_lto": "lto", | |
6739825a | 38 | "coroutine_backend": "with-coroutine", |
c0e705c6 | 39 | "debug": "debug-info", |
119fc611 | 40 | "malloc": "enable-malloc", |
b0b4323e | 41 | "pkgversion": "with-pkgversion", |
c09c1ce7 | 42 | "qemu_firmwarepath": "firmwarepath", |
119fc611 | 43 | "trace_backends": "enable-trace-backends", |
4fda6011 | 44 | "trace_file": "with-trace-file", |
119fc611 PB |
45 | } |
46 | ||
a70248db | 47 | BUILTIN_OPTIONS = { |
c54b59ee PB |
48 | "b_coverage", |
49 | "b_lto", | |
c09c1ce7 | 50 | "datadir", |
c0e705c6 | 51 | "debug", |
c09c1ce7 PB |
52 | "includedir", |
53 | "libdir", | |
54 | "libexecdir", | |
55 | "localedir", | |
56 | "localstatedir", | |
57 | "mandir", | |
a70248db | 58 | "strip", |
c09c1ce7 | 59 | "sysconfdir", |
a70248db PB |
60 | } |
61 | ||
3b4da132 PB |
62 | LINE_WIDTH = 76 |
63 | ||
64 | ||
65 | # Convert the default value of an option to the string used in | |
66 | # the help message | |
808d15b3 PB |
67 | def get_help(opt): |
68 | if opt["name"] == "libdir": | |
69 | return 'system default' | |
70 | value = opt["value"] | |
3b4da132 PB |
71 | if isinstance(value, list): |
72 | return ",".join(value) | |
73 | if isinstance(value, bool): | |
74 | return "enabled" if value else "disabled" | |
75 | return str(value) | |
76 | ||
77 | ||
78 | def wrap(left, text, indent): | |
79 | spaces = " " * indent | |
80 | if len(left) >= indent: | |
81 | yield left | |
82 | left = spaces | |
83 | else: | |
84 | left = (left + spaces)[0:indent] | |
85 | yield from textwrap.wrap( | |
86 | text, width=LINE_WIDTH, initial_indent=left, subsequent_indent=spaces | |
87 | ) | |
88 | ||
89 | ||
61d63097 PB |
90 | def sh_print(line=""): |
91 | print(' printf "%s\\n"', shlex.quote(line)) | |
92 | ||
93 | ||
3b4da132 PB |
94 | def help_line(left, opt, indent, long): |
95 | right = f'{opt["description"]}' | |
96 | if long: | |
808d15b3 | 97 | value = get_help(opt) |
119fc611 | 98 | if value != "auto" and value != "": |
3b4da132 PB |
99 | right += f" [{value}]" |
100 | if "choices" in opt and long: | |
101 | choices = "/".join(sorted(opt["choices"])) | |
102 | right += f" (choices: {choices})" | |
103 | for x in wrap(" " + left, right, indent): | |
104 | sh_print(x) | |
105 | ||
106 | ||
107 | # Return whether the option (a dictionary) can be used with | |
108 | # arguments. Booleans can never be used with arguments; | |
109 | # combos allow an argument only if they accept other values | |
110 | # than "auto", "enabled", and "disabled". | |
111 | def allow_arg(opt): | |
112 | if opt["type"] == "boolean": | |
113 | return False | |
114 | if opt["type"] != "combo": | |
115 | return True | |
116 | return not (set(opt["choices"]) <= {"auto", "disabled", "enabled"}) | |
117 | ||
118 | ||
119fc611 PB |
119 | # Return whether the option (a dictionary) can be used without |
120 | # arguments. Booleans can only be used without arguments; | |
121 | # combos require an argument if they accept neither "enabled" | |
122 | # nor "disabled" | |
123 | def require_arg(opt): | |
124 | if opt["type"] == "boolean": | |
125 | return False | |
126 | if opt["type"] != "combo": | |
127 | return True | |
128 | return not ({"enabled", "disabled"}.intersection(opt["choices"])) | |
129 | ||
130 | ||
a70248db PB |
131 | def filter_options(json): |
132 | if ":" in json["name"]: | |
133 | return False | |
134 | if json["section"] == "user": | |
135 | return json["name"] not in SKIP_OPTIONS | |
136 | else: | |
137 | return json["name"] in BUILTIN_OPTIONS | |
138 | ||
139 | ||
61d63097 | 140 | def load_options(json): |
a70248db | 141 | json = [x for x in json if filter_options(x)] |
61d63097 PB |
142 | return sorted(json, key=lambda x: x["name"]) |
143 | ||
144 | ||
119fc611 PB |
145 | def cli_option(opt): |
146 | name = opt["name"] | |
147 | if name in OPTION_NAMES: | |
148 | return OPTION_NAMES[name] | |
149 | return name.replace("_", "-") | |
150 | ||
151 | ||
152 | def cli_help_key(opt): | |
153 | key = cli_option(opt) | |
154 | if require_arg(opt): | |
155 | return key | |
156 | if opt["type"] == "boolean" and opt["value"]: | |
157 | return f"disable-{key}" | |
158 | return f"enable-{key}" | |
159 | ||
160 | ||
161 | def cli_metavar(opt): | |
162 | if opt["type"] == "string": | |
163 | return "VALUE" | |
164 | if opt["type"] == "array": | |
8154f5e6 | 165 | return "CHOICES" if "choices" in opt else "VALUES" |
119fc611 PB |
166 | return "CHOICE" |
167 | ||
168 | ||
61d63097 PB |
169 | def print_help(options): |
170 | print("meson_options_help() {") | |
119fc611 PB |
171 | for opt in sorted(options, key=cli_help_key): |
172 | key = cli_help_key(opt) | |
3b4da132 PB |
173 | # The first section includes options that have an arguments, |
174 | # and booleans (i.e., only one of enable/disable makes sense) | |
119fc611 PB |
175 | if require_arg(opt): |
176 | metavar = cli_metavar(opt) | |
177 | left = f"--{key}={metavar}" | |
178 | help_line(left, opt, 27, True) | |
179 | elif opt["type"] == "boolean": | |
180 | left = f"--{key}" | |
3b4da132 PB |
181 | help_line(left, opt, 27, False) |
182 | elif allow_arg(opt): | |
183 | if opt["type"] == "combo" and "enabled" in opt["choices"]: | |
119fc611 | 184 | left = f"--{key}[=CHOICE]" |
3b4da132 | 185 | else: |
119fc611 | 186 | left = f"--{key}=CHOICE" |
3b4da132 PB |
187 | help_line(left, opt, 27, True) |
188 | ||
61d63097 PB |
189 | sh_print() |
190 | sh_print("Optional features, enabled with --enable-FEATURE and") | |
191 | sh_print("disabled with --disable-FEATURE, default is enabled if available") | |
192 | sh_print("(unless built with --without-default-features):") | |
193 | sh_print() | |
3b4da132 PB |
194 | for opt in options: |
195 | key = opt["name"].replace("_", "-") | |
196 | if opt["type"] != "boolean" and not allow_arg(opt): | |
197 | help_line(key, opt, 18, False) | |
61d63097 PB |
198 | print("}") |
199 | ||
200 | ||
201 | def print_parse(options): | |
202 | print("_meson_option_parse() {") | |
203 | print(" case $1 in") | |
3b4da132 | 204 | for opt in options: |
119fc611 | 205 | key = cli_option(opt) |
3b4da132 | 206 | name = opt["name"] |
119fc611 | 207 | if require_arg(opt): |
8154f5e6 AO |
208 | if opt["type"] == "array" and not "choices" in opt: |
209 | print(f' --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;') | |
210 | else: | |
211 | print(f' --{key}=*) quote_sh "-D{name}=$2" ;;') | |
119fc611 | 212 | elif opt["type"] == "boolean": |
3b4da132 PB |
213 | print(f' --enable-{key}) printf "%s" -D{name}=true ;;') |
214 | print(f' --disable-{key}) printf "%s" -D{name}=false ;;') | |
215 | else: | |
216 | if opt["type"] == "combo" and "enabled" in opt["choices"]: | |
217 | print(f' --enable-{key}) printf "%s" -D{name}=enabled ;;') | |
218 | if opt["type"] == "combo" and "disabled" in opt["choices"]: | |
219 | print(f' --disable-{key}) printf "%s" -D{name}=disabled ;;') | |
220 | if allow_arg(opt): | |
221 | print(f' --enable-{key}=*) quote_sh "-D{name}=$2" ;;') | |
61d63097 PB |
222 | print(" *) return 1 ;;") |
223 | print(" esac") | |
224 | print("}") | |
225 | ||
226 | ||
227 | options = load_options(json.load(sys.stdin)) | |
228 | print("# This file is generated by meson-buildoptions.py, do not edit!") | |
229 | print_help(options) | |
230 | print_parse(options) |