| 
							- #
 - # Copyright (C) 2017 Karl Linden
 - #
 - # Redistribution and use in source and binary forms, with or without
 - # modification, are permitted provided that the following conditions are
 - # met:
 - #
 - # 1. Redistributions of source code must retain the above copyright
 - #    notice, this list of conditions and the following disclaimer.
 - #
 - # 2. Redistributions in binary form must reproduce the above copyright
 - #    notice, this list of conditions and the following disclaimer in the
 - #    documentation and/or other materials provided with the
 - #    distribution.
 - #
 - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 - # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 - # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 - # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 - # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 - # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 - # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 - # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 - # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 - # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 - # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 - #
 - 
 - import optparse
 - import sys
 - from waflib import Configure, Logs, Options, Utils
 - 
 - # A list of AutoOptions. It is local to each module, so all modules that
 - # use AutoOptions need to run both opt.load and conf.load. In contrast
 - # to the define and style options this does not need to and cannot be
 - # declared in the OptionsContext, because it is needed both for the
 - # options and the configure phase.
 - auto_options = []
 - 
 - class AutoOption:
 -     """
 -     This class represents an auto option that can be used in conjunction
 -     with the waf build system. By default it adds options --foo and
 -     --no-foo respectively to turn on or off foo respectively.
 -     Furthermore it incorporats logic and checks that are required for
 -     these features.
 - 
 -     An option can have an arbitrary number of dependencies that must be
 -     present for the option to be enabled. An option can be enabled or
 -     disabled by default. Here is how the logic works:
 -      1. If the option is explicitly disabled, through --no-foo, then no
 -         checks are made and the option is disabled.
 -      2. If the option is explicitly enabled, through --foo, then check
 -         for all required dependencies, and if some of them are not
 -         found, then print a fatal error telling the user there were
 -         dependencies missing.
 -      3. Otherwise, if the option is enabled by default, then check for
 -         all dependencies. If all dependencies are found the option is
 -         enabled. Otherwise it is disabled.
 -      4. Lastly, if no option was given and the option is disabled by
 -         default, then no checks are performed and the option is
 -         disabled.
 - 
 -     To add a dependency to an option use the check, check_cfg and
 -     find_program methods of this class. The methods are merely small
 -     wrappers around their configuration context counterparts and behave
 -     identically. Note that adding dependencies is done in the options
 -     phase and not in the configure phase, although the checks are
 -     actually executed during the configure phase.
 - 
 -     Custom check functions can be added using the add_function method.
 -     As with the other checks the check function will be invoked during
 -     the configuration. Refer to the documentation of the add_function
 -     method for details.
 - 
 -     When all checks have been made and the class has made a decision the
 -     result is saved in conf.env['NAME'] where 'NAME' by default is the
 -     uppercase of the name argument to __init__, with hyphens replaced by
 -     underscores. This default can be changed with the conf_dest argument
 -     to __init__.
 - 
 -     The class will define a preprocessor symbol with the result. The
 -     default name is WITH_NAME, to not collide with the standard define
 -     of check_cfg, but it can be changed using the define argument to
 -     __init__. It can also be changed globally using
 -     set_auto_options_define.
 -     """
 - 
 -     def __init__(self, opt, name, help=None, default=True,
 -             conf_dest=None, define=None, style=None):
 -         """
 -         Class initializing method.
 - 
 -         Arguments:
 -             opt       OptionsContext
 -             name      name of the option, e.g. alsa
 -             help      help text that will be displayed in --help output
 -             conf_dest conf.env variable to define to the result
 -             define    the preprocessor symbol to define with the result
 -             style     the option style to use; see below for options
 -         """
 - 
 -         # The dependencies to check for. The elements are on the form
 -         # (func, k, kw) where func is the function or function name that
 -         # is used for the check and k and kw are the arguments and
 -         # options to give the function.
 -         self.deps = []
 - 
 -         # Whether or not the option should be enabled. None indicates
 -         # that the checks have not been performed yet.
 -         self.enable = None
 - 
 -         self.help = help
 -         if help:
 -             if default:
 -                 help_comment = ' (enabled by default if possible)'
 -             else:
 -                 help_comment = ' (disabled by default)'
 -             option_help = help + help_comment
 -             no_option_help = None
 -         else:
 -             option_help = no_option_help = optparse.SUPPRESS_HELP
 - 
 -         self.dest = 'auto_option_' + name
 - 
 -         self.default = default
 - 
 -         safe_name = Utils.quote_define_name(name)
 -         self.conf_dest = conf_dest or safe_name
 - 
 -         default_define = opt.get_auto_options_define()
 -         self.define = define or default_define % safe_name
 - 
 -         if not style:
 -             style = opt.get_auto_options_style()
 -         self.style = style
 - 
 -         # plain (default):
 -         #   --foo | --no-foo
 -         # yesno:
 -         #   --foo=yes | --foo=no
 -         # yesno_and_hack:
 -         #  --foo[=yes] | --foo=no or --no-foo
 -         # enable:
 -         #  --enable-foo | --disble-foo
 -         # with:
 -         #  --with-foo | --without-foo
 -         if style in ['plain', 'yesno', 'yesno_and_hack']:
 -             self.no_option = '--no-' + name
 -             self.yes_option = '--' + name
 -         elif style == 'enable':
 -             self.no_option = '--disable-' + name
 -             self.yes_option = '--enable-' + name
 -         elif style == 'with':
 -             self.no_option = '--without-' + name
 -             self.yes_option = '--with-' + name
 -         else:
 -             opt.fatal('invalid style')
 - 
 -         if style in ['yesno', 'yesno_and_hack']:
 -             opt.add_option(
 -                     self.yes_option,
 -                     dest=self.dest,
 -                     action='store',
 -                     choices=['auto', 'no', 'yes'],
 -                     default='auto',
 -                     help=option_help,
 -                     metavar='no|yes')
 -         else:
 -             opt.add_option(
 -                     self.yes_option,
 -                     dest=self.dest,
 -                     action='store_const',
 -                     const='yes',
 -                     default='auto',
 -                     help=option_help)
 -             opt.add_option(
 -                     self.no_option,
 -                     dest=self.dest,
 -                     action='store_const',
 -                     const='no',
 -                     default='auto',
 -                     help=no_option_help)
 - 
 -     def check(self, *k, **kw):
 -         self.deps.append(('check', k, kw))
 -     def check_cfg(self, *k, **kw):
 -         self.deps.append(('check_cfg', k, kw))
 -     def find_program(self, *k, **kw):
 -         self.deps.append(('find_program', k, kw))
 - 
 -     def add_function(self, func, *k, **kw):
 -         """
 -         Add a custom function to be invoked as part of the
 -         configuration. During the configuration the function will be
 -         invoked with the configuration context as first argument
 -         followed by the arguments to this method, except for the func
 -         argument. The function must print a 'Checking for...' message,
 -         because it is referred to if the check fails and this option is
 -         requested.
 - 
 -         On configuration error the function shall raise
 -         conf.errors.ConfigurationError.
 -         """
 -         self.deps.append((func, k, kw))
 - 
 -     def _check(self, conf, required):
 -         """
 -         This private method checks all dependencies. It checks all
 -         dependencies (even if some dependency was not found) so that the
 -         user can install all missing dependencies in one go, instead of
 -         playing the infamous hit-configure-hit-configure game.
 - 
 -         This function returns True if all dependencies were found and
 -         False otherwise.
 -         """
 -         all_found = True
 - 
 -         for (f,k,kw) in self.deps:
 -             if hasattr(f, '__call__'):
 -                 # This is a function supplied by add_function.
 -                 func = f
 -                 k = list(k)
 -                 k.insert(0, conf)
 -                 k = tuple(k)
 -             else:
 -                 func = getattr(conf, f)
 - 
 -             try:
 -                 func(*k, **kw)
 -             except conf.errors.ConfigurationError:
 -                 all_found = False
 -                 if required:
 -                     Logs.error('The above check failed, but the '
 -                                'checkee is required for %s.' %
 -                                self.yes_option)
 - 
 -         return all_found
 - 
 -     def configure(self, conf):
 -         """
 -         This function configures the option examining the command line
 -         option. It sets self.enable to whether this options should be
 -         enabled or not, that is True or False respectively. If not all
 -         dependencies were found self.enable will be False.
 -         conf.env['NAME'] and a preprocessor symbol will be defined with
 -         the result.
 - 
 -         If the option was desired but one or more dependencies were not
 -         found the an error message will be printed for each missing
 -         dependency.
 - 
 -         This function returns True on success and False on if the option
 -         was requested but cannot be enabled.
 -         """
 -         # If the option has already been configured once, do not
 -         # configure it again.
 -         if self.enable != None:
 -             return True
 - 
 -         argument = getattr(Options.options, self.dest)
 -         if argument == 'no':
 -             self.enable = False
 -             retvalue = True
 -         elif argument == 'yes':
 -             retvalue = self.enable = self._check(conf, True)
 -         else:
 -             self.enable = self.default and self._check(conf, False)
 -             retvalue = True
 - 
 -         conf.env[self.conf_dest] = self.enable
 -         conf.define(self.define, int(self.enable))
 -         return retvalue
 - 
 -     def summarize(self, conf):
 -         """
 -         This function displays a result summary with the help text and
 -         the result of the configuration.
 -         """
 -         if self.help:
 -             if self.enable:
 -                 conf.msg(self.help, 'yes', color='GREEN')
 -             else:
 -                 conf.msg(self.help, 'no', color='YELLOW')
 - 
 - def options(opt):
 -     """
 -     This function declares necessary variables in the option context.
 -     The reason for saving variables in the option context is to allow
 -     autooptions to be loaded from modules (which will receive a new
 -     instance of this module, clearing any global variables) with a
 -     uniform style and default in the entire project.
 - 
 -     Call this function through opt.load('autooptions').
 -     """
 -     if not hasattr(opt, 'auto_options_style'):
 -         opt.auto_options_style = 'plain'
 -     if not hasattr(opt, 'auto_options_define'):
 -         opt.auto_options_define = 'WITH_%s'
 - 
 - def opt(f):
 -     """
 -     Decorator: attach a new option function to Options.OptionsContext.
 - 
 -     :param f: method to bind
 -     :type f: function
 -     """
 -     setattr(Options.OptionsContext, f.__name__, f)
 - 
 - @opt
 - def add_auto_option(self, *k, **kw):
 -     """
 -     This function adds an AutoOption to the options context. It takes
 -     the same arguments as the initializer function of the AutoOptions
 -     class.
 -     """
 -     option = AutoOption(self, *k, **kw)
 -     auto_options.append(option)
 -     return option
 - 
 - @opt
 - def get_auto_options_define(self):
 -     """
 -     This function gets the default define name. This default can be
 -     changed through set_auto_optoins_define.
 -     """
 -     return self.auto_options_define
 - 
 - @opt
 - def set_auto_options_define(self, define):
 -     """
 -     This function sets the default define name. The default is
 -     'WITH_%s', where %s will be replaced with the name of the option in
 -     uppercase.
 -     """
 -     self.auto_options_define = define
 - 
 - @opt
 - def get_auto_options_style(self):
 -     """
 -     This function gets the default option style, which will be used for
 -     the subsequent options.
 -     """
 -     return self.auto_options_style
 - 
 - @opt
 - def set_auto_options_style(self, style):
 -     """
 -     This function sets the default option style, which will be used for
 -     the subsequent options.
 -     """
 -     self.auto_options_style = style
 - 
 - @opt
 - def apply_auto_options_hack(self):
 -     """
 -     This function applies the hack necessary for the yesno_and_hack
 -     option style. The hack turns --foo into --foo=yes and --no-foo into
 -     --foo=no.
 - 
 -     It must be called before options are parsed, that is before the
 -     configure phase.
 -     """
 -     for option in auto_options:
 -         # With the hack the yesno options simply extend plain options.
 -         if option.style == 'yesno_and_hack':
 -             for i in range(1, len(sys.argv)):
 -                 if sys.argv[i] == option.yes_option:
 -                     sys.argv[i] = option.yes_option + '=yes'
 -                 elif sys.argv[i] == option.no_option:
 -                     sys.argv[i] = option.yes_option + '=no'
 - 
 - @Configure.conf
 - def summarize_auto_options(self):
 -     """
 -     This function prints a summary of the configuration of the auto
 -     options. Obviously, it must be called after
 -     conf.load('autooptions').
 -     """
 -     for option in auto_options:
 -         option.summarize(self)
 - 
 - def configure(conf):
 -     """
 -     This configures all auto options. Call it through
 -     conf.load('autooptions').
 -     """
 -     ok = True
 -     for option in auto_options:
 -         if not option.configure(conf):
 -             ok = False
 -     if not ok:
 -         conf.fatal('Some requested options had unsatisfied ' +
 -                 'dependencies.\n' +
 -                 'See the above configuration for details.')
 
 
  |