summaryrefslogtreecommitdiffstats
path: root/waflib/Options.py
diff options
context:
space:
mode:
Diffstat (limited to 'waflib/Options.py')
-rw-r--r--waflib/Options.py342
1 files changed, 342 insertions, 0 deletions
diff --git a/waflib/Options.py b/waflib/Options.py
new file mode 100644
index 0000000..ad802d4
--- /dev/null
+++ b/waflib/Options.py
@@ -0,0 +1,342 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Scott Newton, 2005 (scottn)
+# Thomas Nagy, 2006-2018 (ita)
+
+"""
+Support for waf command-line options
+
+Provides default and command-line options, as well the command
+that reads the ``options`` wscript function.
+"""
+
+import os, tempfile, optparse, sys, re
+from waflib import Logs, Utils, Context, Errors
+
+options = optparse.Values()
+"""
+A global dictionary representing user-provided command-line options::
+
+ $ waf --foo=bar
+"""
+
+commands = []
+"""
+List of commands to execute extracted from the command-line. This list
+is consumed during the execution by :py:func:`waflib.Scripting.run_commands`.
+"""
+
+envvars = []
+"""
+List of environment variable declarations placed after the Waf executable name.
+These are detected by searching for "=" in the remaining arguments.
+You probably do not want to use this.
+"""
+
+lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform)
+"""
+Name of the lock file that marks a project as configured
+"""
+
+class opt_parser(optparse.OptionParser):
+ """
+ Command-line options parser.
+ """
+ def __init__(self, ctx, allow_unknown=False):
+ optparse.OptionParser.__init__(self, conflict_handler='resolve', add_help_option=False,
+ version='waf %s (%s)' % (Context.WAFVERSION, Context.WAFREVISION))
+ self.formatter.width = Logs.get_term_cols()
+ self.ctx = ctx
+ self.allow_unknown = allow_unknown
+
+ def _process_args(self, largs, rargs, values):
+ """
+ Custom _process_args to allow unknown options according to the allow_unknown status
+ """
+ while rargs:
+ try:
+ optparse.OptionParser._process_args(self,largs,rargs,values)
+ except (optparse.BadOptionError, optparse.AmbiguousOptionError) as e:
+ if self.allow_unknown:
+ largs.append(e.opt_str)
+ else:
+ self.error(str(e))
+
+ def print_usage(self, file=None):
+ return self.print_help(file)
+
+ def get_usage(self):
+ """
+ Builds the message to print on ``waf --help``
+
+ :rtype: string
+ """
+ cmds_str = {}
+ for cls in Context.classes:
+ if not cls.cmd or cls.cmd == 'options' or cls.cmd.startswith( '_' ):
+ continue
+
+ s = cls.__doc__ or ''
+ cmds_str[cls.cmd] = s
+
+ if Context.g_module:
+ for (k, v) in Context.g_module.__dict__.items():
+ if k in ('options', 'init', 'shutdown'):
+ continue
+
+ if type(v) is type(Context.create_context):
+ if v.__doc__ and not k.startswith('_'):
+ cmds_str[k] = v.__doc__
+
+ just = 0
+ for k in cmds_str:
+ just = max(just, len(k))
+
+ lst = [' %s: %s' % (k.ljust(just), v) for (k, v) in cmds_str.items()]
+ lst.sort()
+ ret = '\n'.join(lst)
+
+ return '''waf [commands] [options]
+
+Main commands (example: ./waf build -j4)
+%s
+''' % ret
+
+
+class OptionsContext(Context.Context):
+ """
+ Collects custom options from wscript files and parses the command line.
+ Sets the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.
+ """
+ cmd = 'options'
+ fun = 'options'
+
+ def __init__(self, **kw):
+ super(OptionsContext, self).__init__(**kw)
+
+ self.parser = opt_parser(self)
+ """Instance of :py:class:`waflib.Options.opt_parser`"""
+
+ self.option_groups = {}
+
+ jobs = self.jobs()
+ p = self.add_option
+ color = os.environ.get('NOCOLOR', '') and 'no' or 'auto'
+ if os.environ.get('CLICOLOR', '') == '0':
+ color = 'no'
+ elif os.environ.get('CLICOLOR_FORCE', '') == '1':
+ color = 'yes'
+ p('-c', '--color', dest='colors', default=color, action='store', help='whether to use colors (yes/no/auto) [default: auto]', choices=('yes', 'no', 'auto'))
+ p('-j', '--jobs', dest='jobs', default=jobs, type='int', help='amount of parallel jobs (%r)' % jobs)
+ p('-k', '--keep', dest='keep', default=0, action='count', help='continue despite errors (-kk to try harder)')
+ p('-v', '--verbose', dest='verbose', default=0, action='count', help='verbosity level -v -vv or -vvv [default: 0]')
+ p('--zones', dest='zones', default='', action='store', help='debugging zones (task_gen, deps, tasks, etc)')
+ p('--profile', dest='profile', default=0, action='store_true', help=optparse.SUPPRESS_HELP)
+ p('--pdb', dest='pdb', default=0, action='store_true', help=optparse.SUPPRESS_HELP)
+ p('-h', '--help', dest='whelp', default=0, action='store_true', help="show this help message and exit")
+
+ gr = self.add_option_group('Configuration options')
+ self.option_groups['configure options'] = gr
+
+ gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out')
+ gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top')
+
+ gr.add_option('--no-lock-in-run', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_run')
+ gr.add_option('--no-lock-in-out', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_out')
+ gr.add_option('--no-lock-in-top', action='store_true', default='', help=optparse.SUPPRESS_HELP, dest='no_lock_in_top')
+
+ default_prefix = getattr(Context.g_module, 'default_prefix', os.environ.get('PREFIX'))
+ if not default_prefix:
+ if Utils.unversioned_sys_platform() == 'win32':
+ d = tempfile.gettempdir()
+ default_prefix = d[0].upper() + d[1:]
+ # win32 preserves the case, but gettempdir does not
+ else:
+ default_prefix = '/usr/local/'
+ gr.add_option('--prefix', dest='prefix', default=default_prefix, help='installation prefix [default: %r]' % default_prefix)
+ gr.add_option('--bindir', dest='bindir', help='bindir')
+ gr.add_option('--libdir', dest='libdir', help='libdir')
+
+ gr = self.add_option_group('Build and installation options')
+ self.option_groups['build and install options'] = gr
+ gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output')
+ gr.add_option('--targets', dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"')
+
+ gr = self.add_option_group('Step options')
+ self.option_groups['step options'] = gr
+ gr.add_option('--files', dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')
+
+ default_destdir = os.environ.get('DESTDIR', '')
+
+ gr = self.add_option_group('Installation and uninstallation options')
+ self.option_groups['install/uninstall options'] = gr
+ gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir')
+ gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation')
+ gr.add_option('--distcheck-args', metavar='ARGS', help='arguments to pass to distcheck', default=None, action='store')
+
+ def jobs(self):
+ """
+ Finds the optimal amount of cpu cores to use for parallel jobs.
+ At runtime the options can be obtained from :py:const:`waflib.Options.options` ::
+
+ from waflib.Options import options
+ njobs = options.jobs
+
+ :return: the amount of cpu cores
+ :rtype: int
+ """
+ count = int(os.environ.get('JOBS', 0))
+ if count < 1:
+ if 'NUMBER_OF_PROCESSORS' in os.environ:
+ # on Windows, use the NUMBER_OF_PROCESSORS environment variable
+ count = int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
+ else:
+ # on everything else, first try the POSIX sysconf values
+ if hasattr(os, 'sysconf_names'):
+ if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
+ count = int(os.sysconf('SC_NPROCESSORS_ONLN'))
+ elif 'SC_NPROCESSORS_CONF' in os.sysconf_names:
+ count = int(os.sysconf('SC_NPROCESSORS_CONF'))
+ if not count and os.name not in ('nt', 'java'):
+ try:
+ tmp = self.cmd_and_log(['sysctl', '-n', 'hw.ncpu'], quiet=0)
+ except Errors.WafError:
+ pass
+ else:
+ if re.match('^[0-9]+$', tmp):
+ count = int(tmp)
+ if count < 1:
+ count = 1
+ elif count > 1024:
+ count = 1024
+ return count
+
+ def add_option(self, *k, **kw):
+ """
+ Wraps ``optparse.add_option``::
+
+ def options(ctx):
+ ctx.add_option('-u', '--use', dest='use', default=False,
+ action='store_true', help='a boolean option')
+
+ :rtype: optparse option object
+ """
+ return self.parser.add_option(*k, **kw)
+
+ def add_option_group(self, *k, **kw):
+ """
+ Wraps ``optparse.add_option_group``::
+
+ def options(ctx):
+ gr = ctx.add_option_group('some options')
+ gr.add_option('-u', '--use', dest='use', default=False, action='store_true')
+
+ :rtype: optparse option group object
+ """
+ try:
+ gr = self.option_groups[k[0]]
+ except KeyError:
+ gr = self.parser.add_option_group(*k, **kw)
+ self.option_groups[k[0]] = gr
+ return gr
+
+ def get_option_group(self, opt_str):
+ """
+ Wraps ``optparse.get_option_group``::
+
+ def options(ctx):
+ gr = ctx.get_option_group('configure options')
+ gr.add_option('-o', '--out', action='store', default='',
+ help='build dir for the project', dest='out')
+
+ :rtype: optparse option group object
+ """
+ try:
+ return self.option_groups[opt_str]
+ except KeyError:
+ for group in self.parser.option_groups:
+ if group.title == opt_str:
+ return group
+ return None
+
+ def sanitize_path(self, path, cwd=None):
+ if not cwd:
+ cwd = Context.launch_dir
+ p = os.path.expanduser(path)
+ p = os.path.join(cwd, p)
+ p = os.path.normpath(p)
+ p = os.path.abspath(p)
+ return p
+
+ def parse_cmd_args(self, _args=None, cwd=None, allow_unknown=False):
+ """
+ Just parse the arguments
+ """
+ self.parser.allow_unknown = allow_unknown
+ (options, leftover_args) = self.parser.parse_args(args=_args)
+ envvars = []
+ commands = []
+ for arg in leftover_args:
+ if '=' in arg:
+ envvars.append(arg)
+ elif arg != 'options':
+ commands.append(arg)
+
+ for name in 'top out destdir prefix bindir libdir'.split():
+ # those paths are usually expanded from Context.launch_dir
+ if getattr(options, name, None):
+ path = self.sanitize_path(getattr(options, name), cwd)
+ setattr(options, name, path)
+ return options, commands, envvars
+
+ def init_module_vars(self, arg_options, arg_commands, arg_envvars):
+ options.__dict__.clear()
+ del commands[:]
+ del envvars[:]
+
+ options.__dict__.update(arg_options.__dict__)
+ commands.extend(arg_commands)
+ envvars.extend(arg_envvars)
+
+ for var in envvars:
+ (name, value) = var.split('=', 1)
+ os.environ[name.strip()] = value
+
+ def init_logs(self, options, commands, envvars):
+ Logs.verbose = options.verbose
+ if options.verbose >= 1:
+ self.load('errcheck')
+
+ colors = {'yes' : 2, 'auto' : 1, 'no' : 0}[options.colors]
+ Logs.enable_colors(colors)
+
+ if options.zones:
+ Logs.zones = options.zones.split(',')
+ if not Logs.verbose:
+ Logs.verbose = 1
+ elif Logs.verbose > 0:
+ Logs.zones = ['runner']
+ if Logs.verbose > 2:
+ Logs.zones = ['*']
+
+ def parse_args(self, _args=None):
+ """
+ Parses arguments from a list which is not necessarily the command-line.
+ Initializes the module variables options, commands and envvars
+ If help is requested, prints it and exit the application
+
+ :param _args: arguments
+ :type _args: list of strings
+ """
+ options, commands, envvars = self.parse_cmd_args()
+ self.init_logs(options, commands, envvars)
+ self.init_module_vars(options, commands, envvars)
+
+ def execute(self):
+ """
+ See :py:func:`waflib.Context.Context.execute`
+ """
+ super(OptionsContext, self).execute()
+ self.parse_args()
+ Utils.alloc_process_pool(options.jobs)
+