find dll path on Windows

When running tests on Windows (or for devenv), paths of shared
libraries need to be added to the PATH envvar for Windows to
be able to find them. Meson is currently using the path of the
import lib, which is wrong in many cases.

This fix does two things: if there is a variable bindir
in the pkg-config file, those variable
values are added to the list of path. This is for conan
dependencies, if conan decides to export those paths.
See https://github.com/conan-io/conan/issues/13532 .

The fallback is to replace `lib` by `bin` in the import
library path. This heuristic will work most of the time
(but the bin directory could have a different name,
or the dll itself could have a different name). In all cases,
it cannot be worse than current implementation, and it
solves many cases.
pull/11613/head
Charles Brunet 2 years ago committed by Xavier Claessens
parent 65c22d8c38
commit 03498424d0
  1. 44
      mesonbuild/backend/backends.py

@ -737,6 +737,20 @@ class Backend:
def rpaths_for_non_system_absolute_shared_libraries(self, target: build.BuildTarget, exclude_system: bool = True) -> 'ImmutableListProtocol[str]':
paths: OrderedSet[str] = OrderedSet()
srcdir = self.environment.get_source_dir()
def add_path(libdir: str) -> None:
try:
commonpath = os.path.commonpath((libdir, srcdir))
except ValueError: # when paths are on different drives on Windows
commonpath = ''
if commonpath == srcdir:
rel_to_src = libdir[len(srcdir) + 1:]
assert not os.path.isabs(rel_to_src), f'rel_to_src: {rel_to_src} is absolute'
paths.add(os.path.join(self.build_to_src, rel_to_src))
else:
paths.add(libdir)
for dep in target.external_deps:
if not isinstance(dep, (dependencies.ExternalLibrary, dependencies.PkgConfigDependency)):
continue
@ -756,17 +770,27 @@ class Backend:
if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']:
continue
try:
commonpath = os.path.commonpath((libdir, srcdir))
except ValueError: # when paths are on different drives on Windows
commonpath = ''
if mesonlib.is_windows() and libpath.endswith('.lib'):
if isinstance(dep, dependencies.PkgConfigDependency):
# If by chance pkg-config knows the bin dir...
bindir = dep.get_pkgconfig_variable('bindir', [], default='')
if bindir:
add_path(bindir)
continue
# If the dll is not in the same dir, try to replace 'lib' with 'bin' in the path.
# This is not 100% proof, since the bin dir could be elsewhere or with a different
# name, and the DLL could have a different name as well, but this is better than nothing.
p = Path(libpath).with_suffix('.dll')
if not p.exists():
# replace last occurence:
binpath = '/bin/'.join(p.as_posix().rsplit('/lib/', maxsplit=1))
if Path(binpath).exists():
libdir = os.path.dirname(binpath)
add_path(libdir)
if commonpath == srcdir:
rel_to_src = libdir[len(srcdir) + 1:]
assert not os.path.isabs(rel_to_src), f'rel_to_src: {rel_to_src} is absolute'
paths.add(os.path.join(self.build_to_src, rel_to_src))
else:
paths.add(libdir)
# Don't remove rpaths specified by the dependency
paths.difference_update(self.get_rpath_dirs_from_link_args(dep.link_args))
for i in chain(target.link_targets, target.link_whole_targets):

Loading…
Cancel
Save