diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 4dce3f5ffa6c..e1cb6028e888 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -350,6 +350,24 @@ def prepend_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSe self.warn_if_has_name(name) self.held_object.prepend(name, values, kwargs['separator']) + @FeatureNew('environment.prepend_library_path', '1.10.0') + @typed_pos_args('environment.prepend_library_path', build.BuildTarget) + @noKwargs + @InterpreterObject.method('prepend_library_path') + def prepend_library_path_method(self, args: T.Tuple[build.BuildTarget], kwargs: TYPE_kwargs) -> None: + target = args[0] + library_paths: T.Set[str] = set() + host_machine = self.interpreter.environment.machines[mesonlib.MachineChoice.HOST] + if (host_machine.is_windows() or host_machine.is_cygwin()) and isinstance(target, (build.Executable, build.SharedModule)): + # On windows we cannot rely on rpath to run executables from build + # directory. We have to add in PATH the location of every DLL needed. + library_paths.update(self.interpreter.backend.determine_windows_extra_paths(target, [])) + tdir = os.path.join(self.interpreter.environment.get_build_dir(), self.interpreter.backend.get_target_dir(target)) + if isinstance(target, build.SharedLibrary): + library_paths.add(tdir) + new_env = self.interpreter.environment.get_env_for_paths(library_paths, set()) + self.held_object.merge(new_env) + _CONF_DATA_SET_KWS: KwargInfo[T.Optional[str]] = KwargInfo('description', (str, NoneType)) diff --git a/mesonbuild/utils/core.py b/mesonbuild/utils/core.py index a87f77acc14f..21c48ac921be 100644 --- a/mesonbuild/utils/core.py +++ b/mesonbuild/utils/core.py @@ -97,8 +97,9 @@ def merge(self, other: EnvironmentVariables) -> None: if name in self.unset_vars: self.unset_vars.remove(name) if other.unset_vars: - self.can_use_env = False self.unset_vars.update(other.unset_vars) + if not other.can_use_env: + self.can_use_env = False def set(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None: if name in self.unset_vars: diff --git a/test cases/common/288 env lib/meson.build b/test cases/common/288 env lib/meson.build new file mode 100644 index 000000000000..0f763f1928d7 --- /dev/null +++ b/test cases/common/288 env lib/meson.build @@ -0,0 +1,19 @@ +project('library-path', 'c') + +snippets = import('snippets') +snippets.symbol_visibility_header('config.h') + +lib = shared_library('mylib', 'mylib.c', + c_args: '-DLIBRARY_PATH_COMPILATION', +) + +env = environment() +env.prepend_library_path(lib) + +prog = find_program('prog.py') +custom_target( + output: 'dummy.txt', + command: [prog, lib], + env: env, + build_by_default: true, +) diff --git a/test cases/common/288 env lib/mylib.c b/test cases/common/288 env lib/mylib.c new file mode 100644 index 000000000000..ca253f960632 --- /dev/null +++ b/test cases/common/288 env lib/mylib.c @@ -0,0 +1,6 @@ +#include "config.h" + +LIBRARY_PATH_API int foo(void) +{ + return 42; +} diff --git a/test cases/common/288 env lib/prog.py b/test cases/common/288 env lib/prog.py new file mode 100755 index 000000000000..c7efe4d5ad5e --- /dev/null +++ b/test cases/common/288 env lib/prog.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +import ctypes +import sys + +mylib = ctypes.cdll.LoadLibrary(sys.argv[1]) +assert mylib.foo() == 42