aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2025-01-10 15:10:09 +0100
committerEli Schwartz <eschwartz93@gmail.com>2025-03-09 13:05:08 -0400
commit528696300afd3236e173242e1e09d1ac80dfec81 (patch)
treef3989f6d6c49e188201719dd13468e10128a755d
parent9c125a26dbf1b6ecc674df2bd1abc02ca48da2cd (diff)
downloadmeson-528696300afd3236e173242e1e09d1ac80dfec81.zip
meson-528696300afd3236e173242e1e09d1ac80dfec81.tar.gz
meson-528696300afd3236e173242e1e09d1ac80dfec81.tar.bz2
mesonlib: extract and optimize is_parent_path
Introduce an alternative to os.path.commonpath(name, path) == path, which is a common idiom throughout Meson. Call it is_parent_path just like the existing static method in Generator. It is a bit faster and handles drives on Windows without the need for an exception handler. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--mesonbuild/backend/backends.py10
-rw-r--r--mesonbuild/backend/ninjabackend.py4
-rw-r--r--mesonbuild/build.py12
-rw-r--r--mesonbuild/scripts/gtkdochelper.py7
-rw-r--r--mesonbuild/utils/universal.py21
5 files changed, 33 insertions, 21 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 88b3357..9326127 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -28,7 +28,8 @@ from ..compilers import LANGUAGES_USING_LDFLAGS, detect, lang_suffixes
from ..mesonlib import (
File, MachineChoice, MesonException, MesonBugException, OrderedSet,
ExecutableSerialisation, EnvironmentException,
- classify_unity_sources, get_compiler_for_source
+ classify_unity_sources, get_compiler_for_source,
+ is_parent_path,
)
from ..options import OptionKey
@@ -797,12 +798,7 @@ class Backend:
):
continue
- try:
- commonpath = os.path.commonpath((libdir, srcdir))
- except ValueError: # when paths are on different drives on Windows
- commonpath = ''
-
- if commonpath == srcdir:
+ 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'
paths.add(os.path.join(self.build_to_src, rel_to_src))
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 316d225..251e63f 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -31,7 +31,7 @@ from ..mesonlib import (
File, LibType, MachineChoice, MesonBugException, MesonException, OrderedSet, PerMachine,
ProgressBar, quote_arg
)
-from ..mesonlib import get_compiler_for_source, has_path_sep
+from ..mesonlib import get_compiler_for_source, has_path_sep, is_parent_path
from ..options import OptionKey
from .backends import CleanTrees
from ..build import GeneratedList, InvalidArguments
@@ -1713,7 +1713,7 @@ class NinjaBackend(backends.Backend):
# Check if the vala file is in a subdir of --basedir
abs_srcbasedir = os.path.join(self.environment.get_source_dir(), target.get_subdir())
abs_vala_file = os.path.join(self.environment.get_build_dir(), vala_file)
- if PurePath(os.path.commonpath((abs_srcbasedir, abs_vala_file))) == PurePath(abs_srcbasedir):
+ if is_parent_path(abs_srcbasedir, abs_vala_file):
vala_c_subdir = PurePath(abs_vala_file).parent.relative_to(abs_srcbasedir)
vala_c_file = os.path.join(str(vala_c_subdir), vala_c_file)
else:
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 9f3af9f..6463c6f 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -24,7 +24,7 @@ from .mesonlib import (
File, MesonException, MachineChoice, PerMachine, OrderedSet, listify,
extract_as_list, typeslistify, stringlistify, classify_unity_sources,
get_filenames_templates_dict, substitute_values, has_path_sep,
- PerMachineDefaultable,
+ is_parent_path, PerMachineDefaultable,
MesonBugException, EnvironmentVariables, pickle_load, lazy_property,
)
from .options import OptionKey
@@ -1824,14 +1824,6 @@ class Generator(HoldableObject):
basename = os.path.splitext(plainname)[0]
return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.arglist]
- @staticmethod
- def is_parent_path(parent: str, trial: str) -> bool:
- try:
- common = os.path.commonpath((parent, trial))
- except ValueError: # Windows on different drives
- return False
- return pathlib.PurePath(common) == pathlib.PurePath(parent)
-
def process_files(self, files: T.Iterable[T.Union[str, File, 'CustomTarget', 'CustomTargetIndex', 'GeneratedList']],
state: T.Union['Interpreter', 'ModuleState'],
preserve_path_from: T.Optional[str] = None,
@@ -1861,7 +1853,7 @@ class Generator(HoldableObject):
for f in fs:
if preserve_path_from:
abs_f = f.absolute_path(state.environment.source_dir, state.environment.build_dir)
- if not self.is_parent_path(preserve_path_from, abs_f):
+ if not is_parent_path(preserve_path_from, abs_f):
raise InvalidArguments('generator.process: When using preserve_path_from, all input files must be in a subdirectory of the given dir.')
f = FileMaybeInTargetPrivateDir(f)
output.add_file(f, state)
diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py
index 0684428..a0b0905 100644
--- a/mesonbuild/scripts/gtkdochelper.py
+++ b/mesonbuild/scripts/gtkdochelper.py
@@ -7,7 +7,10 @@ import sys, os
import subprocess
import shutil
import argparse
-from ..mesonlib import MesonException, Popen_safe, is_windows, is_cygwin, split_args
+from ..mesonlib import (
+ MesonException, Popen_safe, is_windows, is_cygwin, is_parent_path,
+ split_args,
+)
from . import destdir_join
import typing as T
@@ -112,7 +115,7 @@ def build_gtkdoc(source_root: str, build_root: str, doc_subdir: str, src_subdirs
# FIXME: Use mesonlib.File objects so we don't need to do this
if not os.path.isabs(f):
f = os.path.join(doc_src, f)
- elif os.path.commonpath([f, build_root]) == build_root:
+ elif is_parent_path(build_root, f):
continue
shutil.copyfile(f, os.path.join(abs_out, os.path.basename(f)))
diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py
index 45c0b7c..3481aaa 100644
--- a/mesonbuild/utils/universal.py
+++ b/mesonbuild/utils/universal.py
@@ -124,6 +124,7 @@ __all__ = [
'is_netbsd',
'is_openbsd',
'is_osx',
+ 'is_parent_path',
'is_qnx',
'is_sunos',
'is_windows',
@@ -1113,6 +1114,26 @@ def determine_worker_count(varnames: T.Optional[T.List[str]] = None) -> int:
num_workers = 1
return num_workers
+def is_parent_path(parent: str, trial: str) -> bool:
+ '''Checks if @trial is a file under the directory @parent. Both @trial and @parent should be
+ adequately normalized, though empty and '.' segments in @parent and @trial are accepted
+ and discarded, matching the behavior of os.path.commonpath. Either both or none should
+ be absolute.'''
+ assert os.path.isabs(parent) == os.path.isabs(trial)
+ if is_windows():
+ parent = parent.replace('\\', '/')
+ trial = trial.replace('\\', '/')
+
+ split_parent = parent.split('/')
+ split_trial = trial.split('/')
+
+ split_parent = [c for c in split_parent if c and c != '.']
+ split_trial = [c for c in split_trial if c and c != '.']
+
+ components = len(split_parent)
+ return len(split_trial) >= components and split_trial[:components] == split_parent
+
+
def has_path_sep(name: str, sep: str = '/\\') -> bool:
'Checks if any of the specified @sep path separators are in @name'
for each in sep: