diff options
| author | Charles Brunet <charles.brunet@optelgroup.com> | 2025-01-29 16:39:31 -0500 |
|---|---|---|
| committer | Jussi Pakkanen <jussi.pakkanen@mailbox.org> | 2025-08-01 15:54:21 +0300 |
| commit | c554ca55e7493921728645bd082565604f7e17db (patch) | |
| tree | fdbc53d015fbb73468249af3b9032e244f483e0a /mesonbuild/build.py | |
| parent | 8bfe9ef4624180a6344a44fef41418543e2f3c34 (diff) | |
| download | meson-c554ca55e7493921728645bd082565604f7e17db.tar.gz | |
Optimize determine_rpath_dirs
When generating targets in ninja backend for my project,
`determine_rpath_dirs` is the second most expensive function
call. Here are some optimizations:
- early exit when iterating for rpath arguments
- compute system_dirs and external_rpaths once per target instead
of recomputing them for every link args of the target (!!!)
Diffstat (limited to 'mesonbuild/build.py')
| -rw-r--r-- | mesonbuild/build.py | 74 |
1 files changed, 40 insertions, 34 deletions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 8f812c959..9014d09fb 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1808,19 +1808,17 @@ class BuildTarget(Target): self.rpath_dirs_to_remove.update([d.encode('utf-8') for d in result]) return tuple(result) - @staticmethod - def _libdir_is_system(libdir: str, compilers: T.Mapping[str, Compiler], env: environment.Environment) -> bool: - libdir = os.path.normpath(libdir) - for cc in compilers.values(): - if libdir in cc.get_library_dirs(env): - return True - return False - @lru_cache(maxsize=None) def rpaths_for_non_system_absolute_shared_libraries(self, exclude_system: bool = True) -> ImmutableListProtocol[str]: paths: OrderedSet[str] = OrderedSet() srcdir = self.environment.get_source_dir() + system_dirs = set() + if exclude_system: + for cc in self.compilers.values(): + system_dirs.update(cc.get_library_dirs(self.environment)) + + external_rpaths = self.get_external_rpath_dirs() build_to_src = relpath(self.environment.get_source_dir(), self.environment.get_build_dir()) @@ -1828,26 +1826,29 @@ class BuildTarget(Target): if dep.type_name not in {'library', 'pkgconfig', 'cmake'}: continue for libpath in dep.link_args: + if libpath.startswith('-'): + continue # For all link args that are absolute paths to a library file, add RPATH args if not os.path.isabs(libpath): continue - libdir = os.path.dirname(libpath) - if exclude_system and self._libdir_is_system(libdir, self.compilers, self.environment): - # No point in adding system paths. - continue - # Don't remove rpaths specified in LDFLAGS. - if libdir in self.get_external_rpath_dirs(): - continue + libdir, libname = os.path.split(libpath) # Windows doesn't support rpaths, but we use this function to # emulate rpaths by setting PATH # .dll is there for mingw gcc # .so's may be extended with version information, e.g. libxyz.so.1.2.3 if not ( - os.path.splitext(libpath)[1] in {'.dll', '.lib', '.so', '.dylib'} - or re.match(r'.+\.so(\.|$)', os.path.basename(libpath)) + libname.endswith(('.dll', '.lib', '.so', '.dylib')) + or '.so.' in libname ): continue + # Don't remove rpaths specified in LDFLAGS. + if libdir in external_rpaths: + continue + if system_dirs and os.path.normpath(libdir) in system_dirs: + # No point in adding system paths. + continue + if is_parent_path(srcdir, libdir): rel_to_src = libdir[len(srcdir) + 1:] assert not os.path.isabs(rel_to_src), f'rel_to_src: {rel_to_src} is absolute' @@ -1870,33 +1871,38 @@ class BuildTarget(Target): pass return self.get_rpath_dirs_from_link_args(args) - @staticmethod - def get_rpath_dirs_from_link_args(args: T.List[str]) -> T.Set[str]: + # Match rpath formats: + # -Wl,-rpath= + # -Wl,-rpath, + _rpath_regex = re.compile(r'-Wl,-rpath[=,]([^,]+)') + # Match solaris style compat runpath formats: + # -Wl,-R + # -Wl,-R, + _runpath_regex = re.compile(r'-Wl,-R[,]?([^,]+)') + # Match symbols formats: + # -Wl,--just-symbols= + # -Wl,--just-symbols, + _symbols_regex = re.compile(r'-Wl,--just-symbols[=,]([^,]+)') + + @classmethod + def get_rpath_dirs_from_link_args(cls, args: T.List[str]) -> T.Set[str]: dirs: T.Set[str] = set() - # Match rpath formats: - # -Wl,-rpath= - # -Wl,-rpath, - rpath_regex = re.compile(r'-Wl,-rpath[=,]([^,]+)') - # Match solaris style compat runpath formats: - # -Wl,-R - # -Wl,-R, - runpath_regex = re.compile(r'-Wl,-R[,]?([^,]+)') - # Match symbols formats: - # -Wl,--just-symbols= - # -Wl,--just-symbols, - symbols_regex = re.compile(r'-Wl,--just-symbols[=,]([^,]+)') + for arg in args: - rpath_match = rpath_regex.match(arg) + if not arg.startswith('-Wl,'): + continue + + rpath_match = cls._rpath_regex.match(arg) if rpath_match: for dir in rpath_match.group(1).split(':'): dirs.add(dir) - runpath_match = runpath_regex.match(arg) + runpath_match = cls._runpath_regex.match(arg) if runpath_match: for dir in runpath_match.group(1).split(':'): # The symbols arg is an rpath if the path is a directory if os.path.isdir(dir): dirs.add(dir) - symbols_match = symbols_regex.match(arg) + symbols_match = cls._symbols_regex.match(arg) if symbols_match: for dir in symbols_match.group(1).split(':'): # Prevent usage of --just-symbols to specify rpath |
