Skip to content

Commit

Permalink
Optimize determine_rpath_dirs
Browse files Browse the repository at this point in the history
When generating targets in ninja backend for my project,
`determine_rpath_dirs` is the second most expensive function
call. Here are some optimizations, mostly replacing expensive
regex with string manipulation.
  • Loading branch information
bruchar1 committed Jan 29, 2025
1 parent ae1bb2f commit 1bcd3d1
Showing 1 changed file with 33 additions and 24 deletions.
57 changes: 33 additions & 24 deletions mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -724,47 +724,56 @@ def get_external_rpath_dirs(self, target: build.BuildTarget) -> T.Set[str]:
args: T.List[str] = []
for lang in LANGUAGES_USING_LDFLAGS:
try:
e = self.environment.coredata.get_external_link_args(target.for_machine, lang)
if isinstance(e, str):
args.append(e)
else:
args.extend(e)
except Exception:
args += self.environment.coredata.get_external_link_args(target.for_machine, lang)
except KeyError:
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]:
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 rpath_match:
for dir in rpath_match.group(1).split(':'):
dirs.add(dir)
runpath_match = runpath_regex.match(arg)
if runpath_match:
for dir in runpath_match.group(1).split(':'):
if not arg.startswith('-Wl,'):
continue

_wl, argname, *argparts = arg.split(',')
if argname.startswith('-R'):
if len(argname) > 2:
argopt = argname[2:]
else:
argopt = argparts[0]
elif '=' in argname:
argname, argopt = argname.split('=', maxsplit=1)
else:
argopt = argparts[0]

argopts = argopt.split(':')
if argname == '-rpath':
dirs.update(argopts)
elif argname == '-R':
for dir in argopts:
# The symbols arg is an rpath if the path is a directory
if Path(dir).is_dir():
if os.path.isdir(dir):
dirs.add(dir)
symbols_match = symbols_regex.match(arg)
if symbols_match:
for dir in symbols_match.group(1).split(':'):
elif argname == '--just-symbols':
for dir in argopts:
# Prevent usage of --just-symbols to specify rpath
if Path(dir).is_dir():
if os.path.isdir(dir):
raise MesonException(f'Invalid arg for --just-symbols, {dir} is a directory.')

return dirs

@lru_cache(maxsize=None)
Expand All @@ -779,7 +788,7 @@ def rpaths_for_non_system_absolute_shared_libraries(self, target: build.BuildTar
# 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)
libdir, libname = os.path.split(libpath)
if exclude_system and self._libdir_is_system(libdir, target.compilers, self.environment):
# No point in adding system paths.
continue
Expand All @@ -791,8 +800,8 @@ def rpaths_for_non_system_absolute_shared_libraries(self, target: build.BuildTar
# .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

Expand Down

0 comments on commit 1bcd3d1

Please sign in to comment.