diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 8c6e2cdd9..3dc0c9935 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -27,6 +27,7 @@ import os, sys, subprocess, shutil, uuid, re from functools import wraps import importlib +import copy run_depr_printed = False @@ -91,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__() @@ -181,7 +186,7 @@ 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() @@ -211,7 +216,7 @@ class EnvironmentVariablesHolder(InterpreterObject): self.add_var(self.held_object.prepend, args, kwargs) -class ConfigurationDataHolder(InterpreterObject): +class ConfigurationDataHolder(MutableInterpreterObject): def __init__(self): super().__init__() self.used = False # These objects become immutable after use in configure_file. @@ -2455,6 +2460,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'))