3 # Scott Newton, 2005 (scottn)
4 # Thomas Nagy, 2006-2018 (ita)
7 Support for waf command-line options
9 Provides default and command-line options, as well the command
10 that reads the ``options`` wscript function.
13 import os
, tempfile
, optparse
, sys
, re
14 from waflib
import Logs
, Utils
, Context
, Errors
16 options
= optparse
.Values()
18 A global dictionary representing user-provided command-line options::
25 List of commands to execute extracted from the command-line. This list
26 is consumed during the execution by :py:func:`waflib.Scripting.run_commands`.
31 List of environment variable declarations placed after the Waf executable name.
32 These are detected by searching for "=" in the remaining arguments.
33 You probably do not want to use this.
36 lockfile
= os
.environ
.get('WAFLOCK', '.lock-waf_%s_build' % sys
.platform
)
38 Name of the lock file that marks a project as configured
41 class opt_parser(optparse
.OptionParser
):
43 Command-line options parser.
45 def __init__(self
, ctx
, allow_unknown
=False):
46 optparse
.OptionParser
.__init
__(self
, conflict_handler
='resolve', add_help_option
=False,
47 version
='%s %s (%s)' % (Context
.WAFNAME
, Context
.WAFVERSION
, Context
.WAFREVISION
))
48 self
.formatter
.width
= Logs
.get_term_cols()
50 self
.allow_unknown
= allow_unknown
52 def _process_args(self
, largs
, rargs
, values
):
54 Custom _process_args to allow unknown options according to the allow_unknown status
58 optparse
.OptionParser
._process
_args
(self
,largs
,rargs
,values
)
59 except (optparse
.BadOptionError
, optparse
.AmbiguousOptionError
) as e
:
60 if self
.allow_unknown
:
61 largs
.append(e
.opt_str
)
65 def _process_long_opt(self
, rargs
, values
):
66 # --custom-option=-ftxyz is interpreted as -f -t... see #2280
67 if self
.allow_unknown
:
70 optparse
.OptionParser
._process
_long
_opt
(self
, rargs
, values
)
71 except optparse
.BadOptionError
:
78 optparse
.OptionParser
._process
_long
_opt
(self
, rargs
, values
)
80 def print_usage(self
, file=None):
81 return self
.print_help(file)
85 Builds the message to print on ``waf --help``
90 for cls
in Context
.classes
:
91 if not cls
.cmd
or cls
.cmd
== 'options' or cls
.cmd
.startswith( '_' ):
98 for (k
, v
) in Context
.g_module
.__dict
__.items():
99 if k
in ('options', 'init', 'shutdown'):
102 if type(v
) is type(Context
.create_context
):
103 if v
.__doc
__ and not k
.startswith('_'):
104 cmds_str
[k
] = v
.__doc
__
108 just
= max(just
, len(k
))
110 lst
= [' %s: %s' % (k
.ljust(just
), v
) for (k
, v
) in cmds_str
.items()]
114 return '''%s [commands] [options]
116 Main commands (example: ./%s build -j4)
118 ''' % (Context
.WAFNAME
, Context
.WAFNAME
, ret
)
121 class OptionsContext(Context
.Context
):
123 Collects custom options from wscript files and parses the command line.
124 Sets the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.
129 def __init__(self
, **kw
):
130 super(OptionsContext
, self
).__init
__(**kw
)
132 self
.parser
= opt_parser(self
)
133 """Instance of :py:class:`waflib.Options.opt_parser`"""
135 self
.option_groups
= {}
139 color
= os
.environ
.get('NOCOLOR', '') and 'no' or 'auto'
140 if os
.environ
.get('CLICOLOR', '') == '0':
142 elif os
.environ
.get('CLICOLOR_FORCE', '') == '1':
144 p('-c', '--color', dest
='colors', default
=color
, action
='store', help='whether to use colors (yes/no/auto) [default: auto]', choices
=('yes', 'no', 'auto'))
145 p('-j', '--jobs', dest
='jobs', default
=jobs
, type='int', help='amount of parallel jobs (%r)' % jobs
)
146 p('-k', '--keep', dest
='keep', default
=0, action
='count', help='continue despite errors (-kk to try harder)')
147 p('-v', '--verbose', dest
='verbose', default
=0, action
='count', help='verbosity level -v -vv or -vvv [default: 0]')
148 p('--zones', dest
='zones', default
='', action
='store', help='debugging zones (task_gen, deps, tasks, etc)')
149 p('--profile', dest
='profile', default
=0, action
='store_true', help=optparse
.SUPPRESS_HELP
)
150 p('--pdb', dest
='pdb', default
=0, action
='store_true', help=optparse
.SUPPRESS_HELP
)
151 p('-h', '--help', dest
='whelp', default
=0, action
='store_true', help="show this help message and exit")
153 gr
= self
.add_option_group('Configuration options')
154 self
.option_groups
['configure options'] = gr
156 gr
.add_option('-o', '--out', action
='store', default
='', help='build dir for the project', dest
='out')
157 gr
.add_option('-t', '--top', action
='store', default
='', help='src dir for the project', dest
='top')
159 gr
.add_option('--no-lock-in-run', action
='store_true', default
=os
.environ
.get('NO_LOCK_IN_RUN', ''), help=optparse
.SUPPRESS_HELP
, dest
='no_lock_in_run')
160 gr
.add_option('--no-lock-in-out', action
='store_true', default
=os
.environ
.get('NO_LOCK_IN_OUT', ''), help=optparse
.SUPPRESS_HELP
, dest
='no_lock_in_out')
161 gr
.add_option('--no-lock-in-top', action
='store_true', default
=os
.environ
.get('NO_LOCK_IN_TOP', ''), help=optparse
.SUPPRESS_HELP
, dest
='no_lock_in_top')
163 default_prefix
= getattr(Context
.g_module
, 'default_prefix', os
.environ
.get('PREFIX'))
164 if not default_prefix
:
165 if Utils
.unversioned_sys_platform() == 'win32':
166 d
= tempfile
.gettempdir()
167 default_prefix
= d
[0].upper() + d
[1:]
168 # win32 preserves the case, but gettempdir does not
170 default_prefix
= '/usr/local/'
171 gr
.add_option('--prefix', dest
='prefix', default
=default_prefix
, help='installation prefix [default: %r]' % default_prefix
)
172 gr
.add_option('--bindir', dest
='bindir', help='bindir')
173 gr
.add_option('--libdir', dest
='libdir', help='libdir')
175 gr
= self
.add_option_group('Build and installation options')
176 self
.option_groups
['build and install options'] = gr
177 gr
.add_option('-p', '--progress', dest
='progress_bar', default
=0, action
='count', help= '-p: progress bar; -pp: ide output')
178 gr
.add_option('--targets', dest
='targets', default
='', action
='store', help='task generators, e.g. "target1,target2"')
180 gr
= self
.add_option_group('Step options')
181 self
.option_groups
['step options'] = gr
182 gr
.add_option('--files', dest
='files', default
='', action
='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')
184 default_destdir
= os
.environ
.get('DESTDIR', '')
186 gr
= self
.add_option_group('Installation and uninstallation options')
187 self
.option_groups
['install/uninstall options'] = gr
188 gr
.add_option('--destdir', help='installation root [default: %r]' % default_destdir
, default
=default_destdir
, dest
='destdir')
189 gr
.add_option('-f', '--force', dest
='force', default
=False, action
='store_true', help='force file installation')
190 gr
.add_option('--distcheck-args', metavar
='ARGS', help='arguments to pass to distcheck', default
=None, action
='store')
194 Finds the optimal amount of cpu cores to use for parallel jobs.
195 At runtime the options can be obtained from :py:const:`waflib.Options.options` ::
197 from waflib.Options import options
200 :return: the amount of cpu cores
203 count
= int(os
.environ
.get('JOBS', 0))
205 if 'NUMBER_OF_PROCESSORS' in os
.environ
:
206 # on Windows, use the NUMBER_OF_PROCESSORS environment variable
207 count
= int(os
.environ
.get('NUMBER_OF_PROCESSORS', 1))
209 # on everything else, first try the POSIX sysconf values
210 if hasattr(os
, 'sysconf_names'):
211 if 'SC_NPROCESSORS_ONLN' in os
.sysconf_names
:
212 count
= int(os
.sysconf('SC_NPROCESSORS_ONLN'))
213 elif 'SC_NPROCESSORS_CONF' in os
.sysconf_names
:
214 count
= int(os
.sysconf('SC_NPROCESSORS_CONF'))
215 if not count
and os
.name
not in ('nt', 'java'):
217 tmp
= self
.cmd_and_log(['sysctl', '-n', 'hw.ncpu'], quiet
=0)
218 except Errors
.WafError
:
221 if re
.match('^[0-9]+$', tmp
):
229 def add_option(self
, *k
, **kw
):
231 Wraps ``optparse.add_option``::
234 ctx.add_option('-u', '--use', dest='use', default=False,
235 action='store_true', help='a boolean option')
237 :rtype: optparse option object
239 return self
.parser
.add_option(*k
, **kw
)
241 def add_option_group(self
, *k
, **kw
):
243 Wraps ``optparse.add_option_group``::
246 gr = ctx.add_option_group('some options')
247 gr.add_option('-u', '--use', dest='use', default=False, action='store_true')
249 :rtype: optparse option group object
252 gr
= self
.option_groups
[k
[0]]
254 gr
= self
.parser
.add_option_group(*k
, **kw
)
255 self
.option_groups
[k
[0]] = gr
258 def get_option_group(self
, opt_str
):
260 Wraps ``optparse.get_option_group``::
263 gr = ctx.get_option_group('configure options')
264 gr.add_option('-o', '--out', action='store', default='',
265 help='build dir for the project', dest='out')
267 :rtype: optparse option group object
270 return self
.option_groups
[opt_str
]
272 for group
in self
.parser
.option_groups
:
273 if group
.title
== opt_str
:
277 def sanitize_path(self
, path
, cwd
=None):
279 cwd
= Context
.launch_dir
280 p
= os
.path
.expanduser(path
)
281 p
= os
.path
.join(cwd
, p
)
282 p
= os
.path
.normpath(p
)
283 p
= os
.path
.abspath(p
)
286 def parse_cmd_args(self
, _args
=None, cwd
=None, allow_unknown
=False):
288 Just parse the arguments
290 self
.parser
.allow_unknown
= allow_unknown
291 (options
, leftover_args
) = self
.parser
.parse_args(args
=_args
)
294 for arg
in leftover_args
:
297 elif arg
!= 'options':
302 for name
in 'top out destdir prefix bindir libdir'.split():
303 # those paths are usually expanded from Context.launch_dir
304 if getattr(options
, name
, None):
305 path
= self
.sanitize_path(getattr(options
, name
), cwd
)
306 setattr(options
, name
, path
)
307 return options
, commands
, envvars
309 def init_module_vars(self
, arg_options
, arg_commands
, arg_envvars
):
310 options
.__dict
__.clear()
314 options
.__dict
__.update(arg_options
.__dict
__)
315 commands
.extend(arg_commands
)
316 envvars
.extend(arg_envvars
)
319 (name
, value
) = var
.split('=', 1)
320 os
.environ
[name
.strip()] = value
322 def init_logs(self
, options
, commands
, envvars
):
323 Logs
.verbose
= options
.verbose
324 if options
.verbose
>= 1:
325 self
.load('errcheck')
327 colors
= {'yes' : 2, 'auto' : 1, 'no' : 0}[options
.colors
]
328 Logs
.enable_colors(colors
)
331 Logs
.zones
= options
.zones
.split(',')
334 elif Logs
.verbose
> 0:
335 Logs
.zones
= ['runner']
339 def parse_args(self
, _args
=None):
341 Parses arguments from a list which is not necessarily the command-line.
342 Initializes the module variables options, commands and envvars
343 If help is requested, prints it and exit the application
345 :param _args: arguments
346 :type _args: list of strings
348 options
, commands
, envvars
= self
.parse_cmd_args()
349 self
.init_logs(options
, commands
, envvars
)
350 self
.init_module_vars(options
, commands
, envvars
)
354 See :py:func:`waflib.Context.Context.execute`
356 super(OptionsContext
, self
).execute()
358 Utils
.alloc_process_pool(options
.jobs
)