diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index ec82ec95d..d4aacbd1a 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -28,6 +28,7 @@ from .interpreterbase import InterpreterBase from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode from .interpreterbase import InterpreterObject, MutableInterpreterObject +from .modules import ModuleReturnValue import os, sys, shutil, uuid import re @@ -973,6 +974,7 @@ class ModuleHolder(InterpreterObject): raise InvalidArguments('Module %s does not have method %s.' % (self.modname, method_name)) if method_name.startswith('_'): raise InvalidArguments('Function {!r} in module {!r} is private.'.format(method_name, self.modname)) + build_hash = hash(self.interpreter.build) state = ModuleState() state.build_to_src = os.path.relpath(self.interpreter.environment.get_source_dir(), self.interpreter.environment.get_build_dir()) @@ -988,6 +990,8 @@ class ModuleHolder(InterpreterObject): state.global_args = self.interpreter.build.global_args state.project_args = self.interpreter.build.projects_args.get(self.interpreter.subproject, {}) value = fn(state, args, kwargs) + if hash(self.interpreter.build) != build_hash: + raise InterpreterException('Extension module altered internal state illegally.') return self.interpreter.module_method_callback(value) class MesonMain(InterpreterObject): @@ -1227,7 +1231,10 @@ class Interpreter(InterpreterBase): 'join_paths': self.func_join_paths, }) - def module_method_callback(self, invalues): + def module_method_callback(self, return_object): + if not isinstance(return_object, ModuleReturnValue): + raise InterpreterException('Bug in module, it returned an invalid object') + invalues = return_object.new_objects unwrap_single = False if invalues is None: return @@ -1264,7 +1271,7 @@ class Interpreter(InterpreterBase): raise InterpreterException('Module returned a value of unknown type.') if len(outvalues) == 1 and unwrap_single: return outvalues[0] - return outvalues + return return_object.return_value def get_build_def_files(self): return self.build_def_files diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 184d85aef..16cada08d 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -45,6 +45,11 @@ def get_include_args(environment, include_dirs, prefix='-I'): return dirs_str +class ModuleReturnValue: + def __init__(self, return_value, new_objects): + self.return_value = return_value + assert(isinstance(new_objects, list)) + self.new_objects = new_objects class GResourceTarget(build.CustomTarget): def __init__(self, name, subdir, kwargs): diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py index c9247e6bf..dc347e236 100644 --- a/mesonbuild/modules/modtest.py +++ b/mesonbuild/modules/modtest.py @@ -12,10 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +from . import ModuleReturnValue + class TestModule: def print_hello(self, state, args, kwargs): print('Hello from a Meson module') + rv = ModuleReturnValue(None, []) + return rv def initialize(): return TestModule() diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index aaf0746c7..38358f3b2 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -15,6 +15,8 @@ from .. import build from .. import mesonlib from .. import mlog +from . import ModuleReturnValue + import os class PkgConfigModule: @@ -138,7 +140,8 @@ class PkgConfigModule: self.generate_pkgconfig_file(state, libs, subdirs, name, description, url, version, pcfile, pub_reqs, priv_reqs, conflicts, priv_libs) - return build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot) + res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot) + return ModuleReturnValue(res, [res]) def initialize(): return PkgConfigModule()