2 # Copyright (C) 2017 Karl Linden
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
8 # 1. Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 from waflib
import Configure
, Logs
, Options
34 default_define
= 'WITH_%s'
35 default_style
= 'plain'
39 This class represents an auto option that can be used in conjunction
40 with the waf build system. By default it adds options --foo and
41 --no-foo respectively to turn on or off foo respectively.
42 Furthermore it incorporats logic and checks that are required for
45 An option can have an arbitrary number of dependencies that must be
46 present for the option to be enabled. An option can be enabled or
47 disabled by default. Here is how the logic works:
48 1. If the option is explicitly disabled, through --no-foo, then no
49 checks are made and the option is disabled.
50 2. If the option is explicitly enabled, through --foo, then check
51 for all required dependencies, and if some of them are not
52 found, then print a fatal error telling the user there were
54 3. Otherwise, if the option is enabled by default, then check for
55 all dependencies. If all dependencies are found the option is
56 enabled. Otherwise it is disabled.
57 4. Lastly, if no option was given and the option is disabled by
58 default, then no checks are performed and the option is
61 To add a dependency to an option use the check, check_cfg and
62 find_program methods of this class. The methods are merely small
63 wrappers around their configuration context counterparts and behave
64 identically. Note that adding dependencies is done in the options
65 phase and not in the configure phase, although the checks are
66 acutally executed during the configure phase.
68 Custom check functions can be added using the add_function method.
69 As with the other checks the check function will be invoked during
70 the configuration. Refer to the documentation of the add_function
73 When all checks have been made and the class has made a decision the
74 result is saved in conf.env['NAME'] where 'NAME' by default is the
75 uppercase of the name argument to __init__, but it can be changed
76 with the conf_dest argument to __init__.
78 The class will define a preprocessor symbol with the result. The
79 default name is WITH_NAME, to not collide with the standard define
80 of check_cfg, but it can be changed using the define argument to
81 __init__. It can also be changed globally using
82 set_auto_options_define.
85 def __init__(self
, opt
, name
, help, default
=True, conf_dest
=None,
86 define
=None, style
=None):
88 Class initializing method.
92 name name of the option, e.g. alsa
93 help help text that will be displayed in --help output
94 conf_dest conf.env variable to define to the result
95 define the preprocessor symbol to define with the result
96 style the option style to use; see below for options
99 # Dependencies and dependencies that are not found respectively.
100 # elements of both are on the form (func, k, kw) where type
101 # is a string equal to "library", "header", "package" or
102 # "program", func is the function or function name that is used
103 # for the check and k and kw are the arguments and options to
104 # give the check function.
107 # Whether or not the option should be enabled or not. None
108 # indicates that the checks are not done yet.
113 help_comment
= ' (enabled by default if possible)'
115 help_comment
= ' (disabled by default)'
117 self
.dest
= 'auto_option_' + name
119 self
.default
= default
121 self
.conf_dest
= conf_dest
123 self
.conf_dest
= name
.upper()
125 self
.define
= default_define
% name
.upper()
130 style
= default_style
136 # --foo=yes | --foo=no
138 # --foo[=yes] | --foo=no or --no-foo
140 # --enable-foo | --disble-foo
142 # --with-foo | --without-foo
143 if style
in ['plain', 'yesno', 'yesno_and_hack']:
144 self
.no_option
= '--no-' + name
145 self
.yes_option
= '--' + name
146 if style
== 'yesno_and_hack':
148 elif style
== 'enable':
149 self
.no_option
= '--disable-' + name
150 self
.yes_option
= '--enable-' + name
151 elif style
== 'with':
152 self
.no_option
= '--without-' + name
153 self
.yes_option
= '--with-' + name
155 opt
.fatal("invalid style")
157 if style
in ['yesno', 'yesno_and_hack']:
162 choices
=['auto', 'no', 'yes'],
164 help=self
.help + help_comment
,
170 action
='store_const',
173 help=self
.help + help_comment
)
177 action
='store_const',
181 funcs
= ['check', 'check_cfg', 'find_program']
183 def f(*k
, fn
=fn
, **kw
):
184 self
.deps
.append((fn
, k
, kw
))
187 def add_function(self
, func
, *k
, **kw
):
189 Add a custom function to be invoked as part of the
190 configuration. During the configuration the function will be
191 invoked with the configuration context as first argument
192 followed by the arugments to this method, except for the func
193 argument. The function must print a "Checking for..." message,
194 because it is referred to if the check fails and this option is
197 On configuration error the function shall raise
198 conf.errors.ConfigurationError.
200 self
.deps
.append((func
, k
, kw
))
202 def _check(self
, conf
, required
):
204 This private method runs checks all dependencies.
205 It checks all dependencies (even if some dependency was not
206 found) so that the user can install all missing dependencies in
207 one go, instead of playing the infamous
208 hit-configure-hit-configure game.
210 This function returns True if all dependencies were found and
215 for (f
,k
,kw
) in self
.deps
:
216 if hasattr(f
, '__call__'):
217 # This is a function supplied by add_function.
223 func
= getattr(conf
, f
)
226 except conf
.errors
.ConfigurationError
:
229 Logs
.error('The above check failed, but the '
230 'checkee is required for %s.' %
235 def configure(self
, conf
):
237 This function configures the option examining the command line
238 option. It sets self.enable to whether this options should be
239 enabled or not, that is True or False respectively. If not all
240 dependencies were found self.enable will be False.
241 conf.env['NAME'] and a preprocessor symbol will be defined with
244 If the option was desired but one or more dependencies were not
245 found the an error message will be printed for each missing
248 This function returns True on success and False on if the option
249 was requested but cannot be enabled.
251 argument
= getattr(Options
.options
, self
.dest
)
255 elif argument
== 'yes':
256 retvalue
= self
.enable
= self
._check
(conf
, True)
258 self
.enable
= self
.default
and self
._check
(conf
, False)
261 conf
.env
[self
.conf_dest
] = self
.enable
262 conf
.define(self
.define
, int(self
.enable
))
265 def summarize(self
, conf
):
267 This function displays a result summary with the help text and
268 the result of the configuration.
271 conf
.msg(self
.help, 'yes', color
='GREEN')
273 conf
.msg(self
.help, 'no', color
='YELLOW')
277 Decorator: attach a new option function to Options.OptionsContext.
279 :param f: method to bind
282 setattr(Options
.OptionsContext
, f
.__name
__, f
)
285 def add_auto_option(self
, *k
, **kw
):
287 This function adds an AutoOptions to the options context. It takes
288 the same arguments as the initializer funtion of the AutoOptions
291 option
= AutoOption(self
, *k
, **kw
)
292 auto_options
.append(option
)
296 def set_auto_options_define(self
, define
):
298 This function sets the default define name. The default is
299 "WITH_%s", where %s will be replaced with the name of the option in
302 global default_define
303 default_define
= define
306 def set_auto_options_style(self
, style
):
308 This function sets the default option style, which will be used for
309 the subsequent options.
312 default_style
= style
315 def apply_auto_options_hack(self
):
317 This function applies the hack necessary for the yesno_and_hack
318 option style. The hack turns --foo into --foo=yes and --no-foo into
321 It must be called before options are parsed, that is before the
324 for option
in auto_options
:
325 # With the hack the yesno options simply extend plain
327 if option
.style
== 'yesno_and_hack':
328 for i
in range(1, len(sys
.argv
)):
329 if sys
.argv
[i
] == option
.yes_option
:
330 sys
.argv
[i
] = option
.yes_option
+ '=yes'
331 elif sys
.argv
[i
] == option
.no_option
:
332 sys
.argv
[i
] = option
.yes_option
+ '=no'
335 def summarize_auto_options(self
):
337 This function prints a summary of the configuration of the auto
338 options. Obviously, it must be called after
339 conf.load("autooptions").
341 for option
in auto_options
:
342 option
.summarize(self
)
346 This configures all auto options. Call it through
347 conf.load("autooptions").
350 for option
in auto_options
:
351 if not option
.configure(conf
):
354 conf
.fatal('Some requested options had unsatisfied ' +
356 'See the above configuration for details.')