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