diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 00306605b..7b1cb5205 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -92,6 +92,10 @@ class InterpreterObject(): return self.methods[method_name](args, kwargs) raise InvalidCode('Unknown method "%s" in object.' % method_name) +class MutableInterpreterObject(InterpreterObject): + def __init__(self): + super().__init__() + class TryRunResultHolder(InterpreterObject): def __init__(self, res): super().__init__() @@ -182,14 +186,13 @@ class ConfigureFileHolder(InterpreterObject): self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data) -class EnvironmentVariablesHolder(InterpreterObject): +class EnvironmentVariablesHolder(MutableInterpreterObject): def __init__(self): super().__init__() self.held_object = build.EnvironmentVariables() self.methods.update({'set': self.set_method, 'append': self.append_method, 'prepend' : self.prepend_method, - 'copy' : self.copy_method, }) @stringArgs @@ -212,11 +215,8 @@ class EnvironmentVariablesHolder(InterpreterObject): def prepend_method(self, args, kwargs): self.add_var(self.held_object.prepend, args, kwargs) - def copy_method(self, args, kwargs): - return copy.deepcopy(self) - -class ConfigurationDataHolder(InterpreterObject): +class ConfigurationDataHolder(MutableInterpreterObject): def __init__(self): super().__init__() self.used = False # These objects become immutable after use in configure_file. @@ -2461,6 +2461,9 @@ requirements use the version keyword argument instead.''') value = self.to_native(value) if not self.is_assignable(value): raise InvalidCode('Tried to assign an invalid value to variable.') + # For mutable objects we need to make a copy on assignment + if isinstance(value, MutableInterpreterObject): + value = copy.deepcopy(value) self.set_variable(var_name, value) return value diff --git a/test cases/common/121 interpreter copy mutable var on assignment/meson.build b/test cases/common/121 interpreter copy mutable var on assignment/meson.build new file mode 100644 index 000000000..8b15357ad --- /dev/null +++ b/test cases/common/121 interpreter copy mutable var on assignment/meson.build @@ -0,0 +1,20 @@ +project('foo', 'c') + +a = configuration_data() +a.set('HELLO', 1) + +b = a + +assert(a.has('HELLO'), 'Original config data should be set on a') +assert(b.has('HELLO'), 'Original config data should be set on copy') + +configure_file(output : 'b.h', configuration : b) + +# This should still work, as we didn't use the original above but a copy! +a.set('WORLD', 1) + +assert(a.has('WORLD'), 'New config data should have been set') +assert(not b.has('WORLD'), 'New config data set should not affect var copied earlier') + +configure_file(output : 'a.h', configuration : a) + diff --git a/test cases/common/48 test args/env2vars.c b/test cases/common/48 test args/env2vars.c new file mode 100644 index 000000000..19250a8d5 --- /dev/null +++ b/test cases/common/48 test args/env2vars.c @@ -0,0 +1,23 @@ +#include +#include +#include + +int main(int argc, char **argv) { + if(strcmp(getenv("first"), "something-else") != 0) { + fprintf(stderr, "First envvar is wrong. %s\n", getenv("first")); + return 1; + } + if(strcmp(getenv("second"), "val2") != 0) { + fprintf(stderr, "Second envvar is wrong.\n"); + return 1; + } + if(strcmp(getenv("third"), "val3:and_more") != 0) { + fprintf(stderr, "Third envvar is wrong.\n"); + return 1; + } + if(strstr(getenv("PATH"), "fakepath:") != NULL) { + fprintf(stderr, "Third envvar is wrong.\n"); + return 1; + } + return 0; +} diff --git a/test cases/common/48 test args/meson.build b/test cases/common/48 test args/meson.build index 640019863..f599bf7e2 100644 --- a/test cases/common/48 test args/meson.build +++ b/test cases/common/48 test args/meson.build @@ -2,6 +2,7 @@ project('test features', 'c') e1 = executable('cmd_args', 'cmd_args.c') e2 = executable('envvars', 'envvars.c') +e3 = executable('env2vars', 'env2vars.c') env = environment() env.set('first', 'val1') @@ -9,6 +10,12 @@ env.set('second', 'val2') env.set('third', 'val3', 'and_more', separator: ':') env.append('PATH', 'fakepath', separator: ':') +# Make sure environment objects are copied on assignment and we can +# change the copy without affecting the original environment object. +env2 = env +env2.set('first', 'something-else') + test('command line arguments', e1, args : ['first', 'second']) test('environment variables', e2, env : env) +test('environment variables 2', e3, env : env2) test('file arg', find_program('tester.py'), args : files('testfile.txt'))