diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..51429419 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "waf-autooptions"] + path = autooptions + url = ../waf-autooptions diff --git a/autooptions b/autooptions new file mode 160000 index 00000000..cc168226 --- /dev/null +++ b/autooptions @@ -0,0 +1 @@ +Subproject commit cc16822604501c96af265a2e3c51855d2aed635f diff --git a/autooptions/README b/autooptions/README deleted file mode 100644 index 5787838d..00000000 --- a/autooptions/README +++ /dev/null @@ -1,6 +0,0 @@ -Do not modify the code in this directory. It has been copied from its upstream -git repo [1]. When submodules are introduced this directory can be made a -submodule, but until then a verbatim copy is better than inlining the code in -the toplevel wscript. - -[1] https://gitlab.com/karllinden/waf-autooptions diff --git a/autooptions/__init__.py b/autooptions/__init__.py deleted file mode 100644 index 4e8d4018..00000000 --- a/autooptions/__init__.py +++ /dev/null @@ -1,395 +0,0 @@ -# -# 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.')