From 309a5c1510810d3676dcec9962894a3353ce218c Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Wed, 16 Oct 2013 22:33:33 +0300 Subject: [PATCH] Options can be accessed from scripts. --- build.py | 20 +++++++++++---- interpreter.py | 11 ++++++++ meson.py | 7 +++++- optinterpreter.py | 25 +++++++++---------- test cases/common/47 options/meson.build | 9 +++++++ .../common/47 options/meson_options.txt | 2 ++ 6 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 test cases/common/47 options/meson.build create mode 100644 test cases/common/47 options/meson_options.txt diff --git a/build.py b/build.py index 64125a88a..64ea6ac7a 100644 --- a/build.py +++ b/build.py @@ -40,6 +40,16 @@ class Build: self.static_cross_linker = None self.configure_files = [] self.pot = [] + self.user_options = {} + + def merge_options(self, options): + for (name, value) in options.items(): + if name not in self.user_options: + self.user_options[name] = value + else: + oldval = self.user_options[name] + if type(oldval) != type(value): + self.user_options[name] = value def add_compiler(self, compiler): if len(self.compilers) == 0: @@ -82,7 +92,7 @@ class IncludeDirs(): # Fixme: check that the directories actually exist. # Also that they don't contain ".." or somesuch. if len(kwargs) > 0: - raise InvalidCode('Includedirs function does not take keyword arguments.') + raise InvalidArguments('Includedirs function does not take keyword arguments.') def get_curdir(self): return self.curdir @@ -268,15 +278,15 @@ class BuildTarget(): if len(pchlist) == 2: if environment.is_header(pchlist[0]): if not environment.is_source(pchlist[1]): - raise InterpreterException('PCH definition must contain one header and at most one source.') + raise InvalidArguments('PCH definition must contain one header and at most one source.') elif environment.is_source(pchlist[0]): if not environment.is_header(pchlist[1]): - raise InterpreterException('PCH definition must contain one header and at most one source.') + raise InvalidArguments('PCH definition must contain one header and at most one source.') pchlist = [pchlist[1], pchlist[0]] else: - raise InterpreterException('PCH argument %s is of unknown type.' % pchlist[0]) + raise InvalidArguments('PCH argument %s is of unknown type.' % pchlist[0]) elif len(pchlist) > 2: - raise InterpreterException('PCH definition may have a maximum of 2 files.') + raise InvalidArguments('PCH definition may have a maximum of 2 files.') self.pch[language] = pchlist def add_include_dirs(self, args): diff --git a/interpreter.py b/interpreter.py index 4b35234d5..5c3a31718 100644 --- a/interpreter.py +++ b/interpreter.py @@ -580,6 +580,7 @@ class Interpreter(): 'run_command' : self.func_run_command, 'gettext' : self.func_gettext, 'option' : self.func_option, + 'get_option' : self.func_get_option, } def get_build_def_files(self): @@ -696,6 +697,16 @@ class Interpreter(): def func_option(self, nodes, args, kwargs): raise InterpreterException('Tried to call option() in build description file. All options must be in the option file.') + def func_get_option(self, nodes, args, kwargs): + if len(args) != 1: + raise InterpreterException('Argument required for get_option.') + optname = args[0] + if not isinstance(optname, str): + raise InterpreterException('Argument of get_option must be a string.') + if optname not in self.build.user_options: + raise InterpreterException('Tried to access unknown option "%s".' % optname) + return self.build.user_options[optname].value + def func_configuration_data(self, node, args, kwargs): if len(args) != 0: raise InterpreterException('configuration_data takes no arguments') diff --git a/meson.py b/meson.py index d96dffca6..9731d1d87 100755 --- a/meson.py +++ b/meson.py @@ -17,7 +17,7 @@ from optparse import OptionParser import sys, stat, traceback, pickle import os.path -import environment, interpreter +import environment, interpreter, optinterpreter import backends, build import mlog, coredata @@ -121,6 +121,11 @@ itself as required.''' else: mlog.log('Build type:', mlog.bold('native build')) b = build.Build(env) + option_file = os.path.join(self.source_dir, 'meson_options.txt') + if os.path.exists(option_file): + oi = optinterpreter.OptionInterpreter() + oi.process(option_file) + b.merge_options(oi.options) intr = interpreter.Interpreter(b) intr.run() if options.backend == 'ninja': diff --git a/optinterpreter.py b/optinterpreter.py index 01ae441ab..e2f72d071 100644 --- a/optinterpreter.py +++ b/optinterpreter.py @@ -29,9 +29,17 @@ class UserStringOption(UserOption): super().__init__(kwargs) self.value = kwargs.get('value', '') if not isinstance(self.value, str): - raise OptionException('Value of string option is not a string') + raise OptionException('Value of string option is not a string.') + +class UserBooleanOption(UserOption): + def __init__(self, kwargs): + super().__init__(kwargs) + self.value = kwargs.get('value', 'true') + if not isinstance(self.value, bool): + raise OptionException('Value of boolean option is not boolean.') option_types = {'string' : UserStringOption, + 'boolean' : UserBooleanOption, } class OptionInterpreter: @@ -49,17 +57,13 @@ class OptionInterpreter: e.lineno = ast.lineno() raise e statements = ast.get_statements() - i = 0 - while i < len(statements): - cur = statements[i] + for cur in statements: try: self.evaluate_statement(cur) except Exception as e: e.lineno = cur.lineno() - e.file = os.path.join('options.txt') + e.file = os.path.join('meson_options.txt') raise e - i += 1 # In THE FUTURE jump over blocks and stuff. - print(self.options) def reduce_single(self, arg): if isinstance(arg, nodes.AtomExpression) or isinstance(arg, nodes.AtomStatement): @@ -103,13 +107,8 @@ class OptionInterpreter: if not opt_type in option_types: raise OptionException('Unknown type %s.' % opt_type) if len(posargs) != 1: - raise OptionException('Option all must have one (and only one) positional argument') + raise OptionException('Option() must have one (and only one) positional argument') opt_name = posargs[0] if not isinstance(opt_name, str): raise OptionException('Positional argument must be a string.') self.options[opt_name] = option_types[opt_type](kwargs) - -if __name__ == '__main__': - import sys - oi = OptionInterpreter() - oi.process(sys.argv[1]) diff --git a/test cases/common/47 options/meson.build b/test cases/common/47 options/meson.build new file mode 100644 index 000000000..5d6f3d0e5 --- /dev/null +++ b/test cases/common/47 options/meson.build @@ -0,0 +1,9 @@ +project('options', 'c') + +if get_option('testoption') != 'optval' + error('Incorrect value to test option') +endif + +if get_option('other_one') != false + error('Incorrect value to boolean option.') +endif diff --git a/test cases/common/47 options/meson_options.txt b/test cases/common/47 options/meson_options.txt new file mode 100644 index 000000000..3dcb62d02 --- /dev/null +++ b/test cases/common/47 options/meson_options.txt @@ -0,0 +1,2 @@ +option('testoption', type : 'string', value : 'optval') +option('other_one', type : 'boolean', value : false)