diff options
author | Charles Brunet <charles.brunet@optelgroup.com> | 2023-04-04 11:25:36 -0400 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2023-04-11 20:28:23 +0300 |
commit | e238b81ba0b89faa19b512d1e78de00dad1488ce (patch) | |
tree | f26d0a92448b3f92d949e30267b6c22bcc18b015 /mesonbuild | |
parent | 4cf9aab35719470fa71fdfa561ad0921f577f3bb (diff) | |
download | meson-e238b81ba0b89faa19b512d1e78de00dad1488ce.zip meson-e238b81ba0b89faa19b512d1e78de00dad1488ce.tar.gz meson-e238b81ba0b89faa19b512d1e78de00dad1488ce.tar.bz2 |
better algo to find DLL paths on Windows
Instead of using a hacky version of
rpaths_for_non_system_absolute_shared_libraries,
we use a custom adhoc function. The function filters out
paths that do not contain dll files. It also finds paths
from any kind of dependencies.
This removes unneeded paths from the PATH env var,
and adds paths that were missing otherwise.
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/backend/backends.py | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index f1ac4a5..4972eab 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -737,6 +737,7 @@ 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() + for dep in target.external_deps: if not isinstance(dep, (dependencies.ExternalLibrary, dependencies.PkgConfigDependency)): continue @@ -752,8 +753,9 @@ class Backend: if libdir in self.get_external_rpath_dirs(target): continue # Windows doesn't support rpaths, but we use this function to - # emulate rpaths by setting PATH, so also accept DLLs here - if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']: + # emulate rpaths by setting PATH + # .dll is there for mingw gcc + if os.path.splitext(libpath)[1] not in {'.dll', '.lib', '.so', '.dylib'}: continue try: @@ -1059,6 +1061,57 @@ class Backend: paths.update(cc.get_library_dirs(self.environment)) return list(paths) + @classmethod + @lru_cache(maxsize=None) + def extract_dll_paths(cls, target: build.BuildTarget) -> T.Set[str]: + """Find paths to all DLLs needed for a given target, since + we link against import libs, and we don't know the actual + path of the DLLs. + + 1. If there are DLLs in the same directory than the .lib dir, use it + 2. If there is a sibbling directory named 'bin' with DLLs in it, use it + """ + results = set() + for dep in target.external_deps: + + if isinstance(dep, dependencies.PkgConfigDependency): + # If by chance pkg-config knows the bin dir... + bindir = dep.get_pkgconfig_variable('bindir', [], default='') + if bindir: + results.add(bindir) + + for link_arg in dep.link_args: + if link_arg.startswith(('-l', '-L')): + link_arg = link_arg[2:] + p = Path(link_arg) + if not p.is_absolute(): + continue + + try: + p = p.resolve(strict=True) + except FileNotFoundError: + continue + + for _ in p.parent.glob('*.dll'): + # path contains dlls + results.add(str(p.parent)) + break + + else: + if p.is_file(): + p = p.parent + # Heuristic: replace *last* occurence of '/lib' + binpath = Path('/bin'.join(p.as_posix().rsplit('/lib', maxsplit=1))) + for _ in binpath.glob('*.dll'): + results.add(str(binpath)) + break + + for i in chain(target.link_targets, target.link_whole_targets): + if isinstance(i, build.BuildTarget): + results.update(cls.extract_dll_paths(i)) + + return results + def determine_windows_extra_paths( self, target: T.Union[build.BuildTarget, build.CustomTarget, programs.ExternalProgram, mesonlib.File, str], extra_bdeps: T.Sequence[T.Union[build.BuildTarget, build.CustomTarget]]) -> T.List[str]: @@ -1073,8 +1126,8 @@ class Backend: if isinstance(target, build.BuildTarget): prospectives.update(target.get_transitive_link_deps()) # External deps - for deppath in self.rpaths_for_non_system_absolute_shared_libraries(target, exclude_system=False): - result.add(os.path.normpath(os.path.join(self.environment.get_build_dir(), deppath))) + result.update(self.extract_dll_paths(target)) + for bdep in extra_bdeps: prospectives.add(bdep) if isinstance(bdep, build.BuildTarget): @@ -1125,6 +1178,11 @@ class Backend: if isinstance(exe, build.CustomTarget): extra_bdeps = list(exe.get_transitive_build_target_deps()) extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps) + for a in t.cmd_args: + if isinstance(a, build.BuildTarget): + for p in self.determine_windows_extra_paths(a, []): + if p not in extra_paths: + extra_paths.append(p) else: extra_paths = [] @@ -1137,8 +1195,6 @@ class Backend: depends.add(a) elif isinstance(a, build.CustomTargetIndex): depends.add(a.target) - if isinstance(a, build.BuildTarget): - extra_paths += self.determine_windows_extra_paths(a, []) if isinstance(a, mesonlib.File): a = os.path.join(self.environment.get_build_dir(), a.rel_to_builddir(self.build_to_src)) |