aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/coredata.py41
-rw-r--r--mesonbuild/environment.py2
-rw-r--r--mesonbuild/interpreter.py142
-rw-r--r--mesonbuild/optinterpreter.py45
4 files changed, 75 insertions, 155 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index d0521b6..2d44b99 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -301,18 +301,11 @@ class CoreData:
args = [key] + builtin_options[key][1:-1] + [value]
self.builtins[key] = builtin_options[key][0](*args)
- def init_backend_options(self, backend_name, options):
+ def init_backend_options(self, backend_name):
if backend_name == 'ninja':
self.backend_options['backend_max_links'] = UserIntegerOption('backend_max_links',
'Maximum number of linker processes to run or 0 for no limit',
0, None, 0)
- for o in options:
- key, value = o.split('=', 1)
- if not key.startswith('backend_'):
- continue
- if key not in self.backend_options:
- raise MesonException('Unknown backend option %s' % key)
- self.backend_options[key].set_value(value)
def get_builtin_option(self, optname):
if optname in self.builtins:
@@ -497,27 +490,6 @@ def register_builtin_arguments(parser):
parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option",
help='Set the value of an option, can be used several times to set multiple options.')
-def filter_builtin_options(args):
- """Filter out any builtin arguments passed as -- instead of -D.
-
- Error if an argument is passed with -- and -D
- """
- for name in builtin_options:
- cmdline_name = get_builtin_option_cmdline_name(name)
- # Chekc if user passed -Doption=value or --option=value
- has_dashdash = hasattr(args, name)
- has_dashd = any([a.startswith('{}='.format(name)) for a in args.projectoptions])
-
- # Passing both is ambigous, abort
- if has_dashdash and has_dashd:
- raise MesonException(
- 'Got argument {0} as both -D{0} and {1}. Pick one.'.format(name, cmdline_name))
-
- # Pretend --option never existed
- if has_dashdash:
- args.projectoptions.append('{}={}'.format(name, getattr(args, name)))
- delattr(args, name)
-
def create_options_dict(options):
result = {}
for o in options:
@@ -529,9 +501,18 @@ def create_options_dict(options):
return result
def parse_cmd_line_options(args):
- filter_builtin_options(args)
args.cmd_line_options = create_options_dict(args.projectoptions)
+ # Merge builtin options set with --option into the dict.
+ for name in builtin_options:
+ value = getattr(args, name, None)
+ if value is not None:
+ if name in args.cmd_line_options:
+ cmdline_name = get_builtin_option_cmdline_name(name)
+ raise MesonException(
+ 'Got argument {0} as both -D{0} and {1}. Pick one.'.format(name, cmdline_name))
+ args.cmd_line_options[name] = value
+ delattr(args, name)
builtin_options = {
'buildtype': [UserComboOption, 'Build type to use.', ['plain', 'debug', 'debugoptimized', 'release', 'minsize'], 'debug'],
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 9b252a2..074bd75 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -288,7 +288,7 @@ class Environment:
self.cross_info = CrossBuildInfo(self.coredata.cross_file)
else:
self.cross_info = None
- self.cmd_line_options = options
+ self.cmd_line_options = options.cmd_line_options
# List of potential compilers.
if mesonlib.is_windows():
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index ffe942f..86c55e4 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1755,7 +1755,7 @@ permitted_kwargs = {'add_global_arguments': {'language'},
class Interpreter(InterpreterBase):
def __init__(self, build, backend=None, subproject='', subdir='', subproject_dir='subprojects',
- modules = None, default_project_options=[]):
+ modules = None, default_project_options=None):
super().__init__(build.environment.get_source_dir(), subdir)
self.an_unpicklable_object = mesonlib.an_unpicklable_object
self.build = build
@@ -1781,7 +1781,11 @@ class Interpreter(InterpreterBase):
self.global_args_frozen = False # implies self.project_args_frozen
self.subprojects = {}
self.subproject_stack = []
- self.default_project_options = default_project_options[:] # Passed from the outside, only used in subprojects.
+ # Passed from the outside, only used in subprojects.
+ if default_project_options:
+ self.default_project_options = default_project_options.copy()
+ else:
+ self.default_project_options = {}
self.build_func_dict()
# build_def_files needs to be defined before parse_project is called
self.build_def_files = [os.path.join(self.subdir, environment.build_filename)]
@@ -2106,6 +2110,8 @@ external dependencies (including libraries) must go to "dependencies".''')
return self.do_subproject(dirname, kwargs)
def do_subproject(self, dirname, kwargs):
+ default_options = mesonlib.stringlistify(kwargs.get('default_options', []))
+ default_options = coredata.create_options_dict(default_options)
if dirname == '':
raise InterpreterException('Subproject dir name must not be empty.')
if dirname[0] == '.':
@@ -2142,7 +2148,7 @@ external dependencies (including libraries) must go to "dependencies".''')
with mlog.nested():
mlog.log('\nExecuting subproject ', mlog.bold(dirname), '.\n', sep='')
subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir,
- self.modules, mesonlib.stringlistify(kwargs.get('default_options', [])))
+ self.modules, default_options)
subi.subprojects = self.subprojects
subi.subproject_stack = self.subproject_stack + [dirname]
@@ -2206,53 +2212,34 @@ to directly access options of other subprojects.''')
raise InterpreterException('configuration_data takes no arguments')
return ConfigurationDataHolder()
- def parse_default_options(self, default_options):
- default_options = listify(default_options)
- for option in default_options:
- if not isinstance(option, str):
- mlog.debug(option)
- raise InterpreterException('Default options must be strings')
- if '=' not in option:
- raise InterpreterException('All default options must be of type key=value.')
- key, value = option.split('=', 1)
- if coredata.is_builtin_option(key):
- if self.subproject != '':
- continue # Only the master project is allowed to set global options.
- newoptions = [option] + self.environment.cmd_line_options.projectoptions
- self.environment.cmd_line_options.projectoptions = newoptions
- else:
- # Option values set with subproject() default_options override those
- # set in project() default_options.
- pref = key + '='
- for i in self.default_project_options:
- if i.startswith(pref):
- option = i
- break
- # If we are in a subproject, add the subproject prefix to option
- # name.
- if self.subproject != '':
- option = self.subproject + ':' + option
- newoptions = [option] + self.environment.cmd_line_options.projectoptions
- self.environment.cmd_line_options.projectoptions = newoptions
- # Add options that are only in default_options.
- for defopt in self.default_project_options:
- key, value = defopt.split('=')
- pref = key + '='
- for i in default_options:
- if i.startswith(pref):
- break
- else:
- defopt = self.subproject + ':' + defopt
- newoptions = [defopt] + self.environment.cmd_line_options.projectoptions
- self.environment.cmd_line_options.projectoptions = newoptions
-
- def set_builtin_options(self):
- # Create a dict containing only builtin options, then use
- # coredata.set_options() because it already has code to set the prefix
- # option first to sanitize all other options.
- options = coredata.create_options_dict(self.environment.cmd_line_options.projectoptions)
- options = {k: v for k, v in options.items() if coredata.is_builtin_option(k)}
- self.coredata.set_options(options)
+ def set_options(self, default_options):
+ # Set default options as if they were passed to the command line.
+ # Subprojects can only define default for user options.
+ for k, v in default_options.items():
+ if self.subproject:
+ if optinterpreter.is_invalid_name(k):
+ continue
+ k = self.subproject + ':' + k
+ self.environment.cmd_line_options.setdefault(k, v)
+
+ # Create a subset of cmd_line_options, keeping only options for this
+ # subproject. Also take builtin options if it's the main project.
+ # Language and backend specific options will be set later when adding
+ # languages and setting the backend (builtin options must be set first
+ # to know which backend we'll use).
+ options = {}
+ for k, v in self.environment.cmd_line_options.items():
+ if self.subproject:
+ if not k.startswith(self.subproject + ':'):
+ continue
+ elif k not in coredata.get_builtin_options():
+ if ':' in k:
+ continue
+ if optinterpreter.is_invalid_name(k):
+ continue
+ options[k] = v
+
+ self.coredata.set_options(options, self.subproject)
def set_backend(self):
# The backend is already set when parsing subprojects
@@ -2282,7 +2269,10 @@ to directly access options of other subprojects.''')
else:
raise InterpreterException('Unknown backend "%s".' % backend)
- self.coredata.init_backend_options(backend, self.environment.cmd_line_options.projectoptions)
+ self.coredata.init_backend_options(backend)
+
+ options = {k: v for k, v in self.environment.cmd_line_options.items() if k.startswith('backend_')}
+ self.coredata.set_options(options)
@stringArgs
@permittedKwargs(permitted_kwargs['project'])
@@ -2293,20 +2283,20 @@ to directly access options of other subprojects.''')
proj_langs = args[1:]
if ':' in proj_name:
raise InvalidArguments("Project name {!r} must not contain ':'".format(proj_name))
- default_options = kwargs.get('default_options', [])
- if self.environment.first_invocation and (len(default_options) > 0 or
- len(self.default_project_options) > 0):
- self.parse_default_options(default_options)
- if not self.is_subproject():
- self.build.project_name = proj_name
- self.set_builtin_options()
+
if os.path.exists(self.option_file):
- oi = optinterpreter.OptionInterpreter(self.subproject,
- self.build.environment.cmd_line_options.projectoptions,
- )
+ oi = optinterpreter.OptionInterpreter(self.subproject)
oi.process(self.option_file)
self.coredata.merge_user_options(oi.options)
+
+ default_options = mesonlib.stringlistify(kwargs.get('default_options', []))
+ default_options = coredata.create_options_dict(default_options)
+ default_options.update(self.default_project_options)
+ self.set_options(default_options)
self.set_backend()
+
+ if not self.is_subproject():
+ self.build.project_name = proj_name
self.active_projectname = proj_name
self.project_version = kwargs.get('version', 'undefined')
if self.build.project_version is None:
@@ -2450,17 +2440,14 @@ to directly access options of other subprojects.''')
cross_comp.sanity_check(self.environment.get_scratch_dir(), self.environment)
self.coredata.cross_compilers[lang] = cross_comp
new_options.update(cross_comp.get_options())
+
optprefix = lang + '_'
- for i in new_options:
- if not i.startswith(optprefix):
- raise InterpreterException('Internal error, %s has incorrect prefix.' % i)
- cmd_prefix = i + '='
- for cmd_arg in self.environment.cmd_line_options.projectoptions:
- if cmd_arg.startswith(cmd_prefix):
- value = cmd_arg.split('=', 1)[1]
- new_options[i].set_value(value)
- new_options.update(self.coredata.compiler_options)
- self.coredata.compiler_options = new_options
+ for k, o in new_options.items():
+ if not k.startswith(optprefix):
+ raise InterpreterException('Internal error, %s has incorrect prefix.' % k)
+ if k in self.environment.cmd_line_options:
+ o.set_value(self.environment.cmd_line_options[k])
+ self.coredata.compiler_options.setdefault(k, o)
# Unlike compiler and linker flags, preprocessor flags are not in
# compiler_options because they are not visible to user.
@@ -2510,19 +2497,14 @@ to directly access options of other subprojects.''')
def add_base_options(self, compiler):
enabled_opts = []
- proj_opt = self.environment.cmd_line_options.projectoptions
for optname in compiler.base_options:
if optname in self.coredata.base_options:
continue
oobj = compilers.base_options[optname]
- for po in proj_opt:
- if po.startswith(optname + '='):
- opt, value = po.split('=', 1)
- oobj.set_value(value)
- if oobj.value:
- enabled_opts.append(opt)
- break
- self.coredata.base_options[optname] = oobj
+ if optname in self.environment.cmd_line_options:
+ oobj.set_value(self.environment.cmd_line_options[optname])
+ enabled_opts.append(optname)
+ self.coredata. base_options[optname] = oobj
self.emit_base_options_warnings(enabled_opts)
def program_from_cross_file(self, prognames, silent=False):
diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py
index 7455c48..4207f45 100644
--- a/mesonbuild/optinterpreter.py
+++ b/mesonbuild/optinterpreter.py
@@ -15,7 +15,6 @@
import os, re
import functools
-from . import mlog
from . import mparser
from . import coredata
from . import mesonlib
@@ -125,48 +124,9 @@ option_types = {'string': StringParser,
}
class OptionInterpreter:
- def __init__(self, subproject, command_line_options):
+ def __init__(self, subproject):
self.options = {}
self.subproject = subproject
- self.sbprefix = subproject + ':'
- self.cmd_line_options = {}
- for o in command_line_options:
- if self.subproject != '': # Strip the beginning.
- # Ignore options that aren't for this subproject
- if not o.startswith(self.sbprefix):
- continue
- try:
- (key, value) = o.split('=', 1)
- except ValueError:
- raise OptionException('Option {!r} must have a value separated by equals sign.'.format(o))
- # Ignore subproject options if not fetching subproject options
- if self.subproject == '' and ':' in key:
- continue
- self.cmd_line_options[key] = value
-
- def get_bad_options(self):
- subproj_len = len(self.subproject)
- if subproj_len > 0:
- subproj_len += 1
- retval = []
- # The options need to be sorted (e.g. here) to get consistent
- # error messages (on all platforms) which is required by some test
- # cases that check (also) the order of these options.
- for option in sorted(self.cmd_line_options):
- if option in list(self.options) + forbidden_option_names:
- continue
- if any(option[subproj_len:].startswith(p) for p in forbidden_prefixes):
- continue
- retval += [option]
- return retval
-
- def check_for_bad_options(self):
- bad = self.get_bad_options()
- if bad:
- sub = 'In subproject {}: '.format(self.subproject) if self.subproject else ''
- mlog.warning(
- '{}Unknown command line options: "{}"\n'
- 'This will become a hard error in a future Meson release.'.format(sub, ', '.join(bad)))
def process(self, option_file):
try:
@@ -187,7 +147,6 @@ class OptionInterpreter:
e.colno = cur.colno
e.file = os.path.join('meson_options.txt')
raise e
- self.check_for_bad_options()
def reduce_single(self, arg):
if isinstance(arg, str):
@@ -243,6 +202,4 @@ class OptionInterpreter:
opt = option_types[opt_type](opt_name, kwargs.pop('description', ''), kwargs)
if opt.description == '':
opt.description = opt_name
- if opt_name in self.cmd_line_options:
- opt.set_value(self.cmd_line_options[opt_name])
self.options[opt_name] = opt