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