summaryrefslogtreecommitdiff
path: root/mesonbuild/interpreter/interpreter.py
diff options
context:
space:
mode:
authorEli Schwartz <eschwartz93@gmail.com>2025-10-15 21:49:10 -0400
committerEli Schwartz <eschwartz93@gmail.com>2025-10-15 23:01:36 -0400
commit5c0aad57f92d2a6bebc1cb17655dd8a56f4bcd3f (patch)
tree69a228a10f425b33392df576f79bd8b7c5402104 /mesonbuild/interpreter/interpreter.py
parent1177e77c2893891cb35144b8033786cb8f75c7cd (diff)
downloadmeson-5c0aad57f92d2a6bebc1cb17655dd8a56f4bcd3f.tar.gz
revert local_program()
This reverts https://github.com/mesonbuild/meson/pull/15107 Explicit objections regarding the design were raised and not answered, so it shouldn't have been merged. It needs to be discussed and revisited.
Diffstat (limited to 'mesonbuild/interpreter/interpreter.py')
-rw-r--r--mesonbuild/interpreter/interpreter.py140
1 files changed, 43 insertions, 97 deletions
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index 51671bfc5..8481f36bd 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -21,7 +21,7 @@ from ..mesonlib import (EnvironmentVariables, ExecutableSerialisation, MesonBugE
FileMode, MachineChoice, is_parent_path, listify,
extract_as_list, has_path_sep, path_is_in_root, PerMachine)
from ..options import OptionKey
-from ..programs import ExternalProgram, NonExistingExternalProgram, BaseProgram
+from ..programs import ExternalProgram, NonExistingExternalProgram
from ..dependencies import Dependency
from ..depfile import DepFile
from ..interpreterbase import ContainerTypeInfo, InterpreterBase, KwargInfo, typed_kwargs, typed_pos_args
@@ -118,6 +118,7 @@ if T.TYPE_CHECKING:
from ..backend.backends import Backend
from ..interpreterbase.baseobjects import InterpreterObject, TYPE_var, TYPE_kwargs
from ..options import OptionDict
+ from ..programs import OverrideProgram
from .type_checking import SourcesVarargsType
# Input source types passed to Targets
@@ -129,7 +130,7 @@ if T.TYPE_CHECKING:
BuildTargetSource = T.Union[mesonlib.FileOrString, build.GeneratedTypes, build.StructuredSources]
- ProgramVersionFunc = T.Callable[[T.Union[ExternalProgram, build.LocalProgram]], str]
+ ProgramVersionFunc = T.Callable[[T.Union[ExternalProgram, build.Executable, OverrideProgram]], str]
TestClass = T.TypeVar('TestClass', bound=Test)
@@ -368,7 +369,6 @@ class Interpreter(InterpreterBase, HoldableObject):
'executable': self.func_executable,
'files': self.func_files,
'find_program': self.func_find_program,
- 'local_program': self.func_local_program,
'generator': self.func_generator,
'get_option': self.func_get_option,
'get_variable': self.func_get_variable,
@@ -440,6 +440,7 @@ class Interpreter(InterpreterBase, HoldableObject):
build.Generator: OBJ.GeneratorHolder,
build.GeneratedList: OBJ.GeneratedListHolder,
build.ExtractedObjects: OBJ.GeneratedObjectsHolder,
+ build.OverrideExecutable: OBJ.OverrideExecutableHolder,
build.RunTarget: OBJ.RunTargetHolder,
build.AliasTarget: OBJ.AliasTargetHolder,
build.Headers: OBJ.HeadersHolder,
@@ -469,7 +470,7 @@ class Interpreter(InterpreterBase, HoldableObject):
'''
self.bound_holder_map.update({
dependencies.Dependency: OBJ.DependencyHolder,
- BaseProgram: OBJ.BaseProgramHolder,
+ ExternalProgram: OBJ.ExternalProgramHolder,
compilers.Compiler: compilerOBJ.CompilerHolder,
ModuleObject: OBJ.ModuleObjectHolder,
MutableModuleObject: OBJ.MutableModuleObjectHolder,
@@ -768,8 +769,8 @@ class Interpreter(InterpreterBase, HoldableObject):
# better error messages when overridden
@typed_pos_args(
'run_command',
- (build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str, build.LocalProgram),
- varargs=(build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str, build.LocalProgram))
+ (build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str),
+ varargs=(build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str))
@typed_kwargs(
'run_command',
KwargInfo('check', (bool, NoneType), since='0.47.0'),
@@ -777,21 +778,14 @@ class Interpreter(InterpreterBase, HoldableObject):
ENV_KW.evolve(since='0.50.0'),
)
def func_run_command(self, node: mparser.BaseNode,
- args: T.Tuple[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str, build.LocalProgram],
- T.List[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str, build.LocalProgram]]],
+ args: T.Tuple[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str],
+ T.List[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str]]],
kwargs: 'kwtypes.RunCommand') -> RunProcess:
return self.run_command_impl(args, kwargs)
- def _compiled_exe_error(self, cmd: T.Union[build.LocalProgram, build.Executable]) -> T.NoReturn:
- descr = cmd.name if isinstance(cmd, build.Executable) else cmd.description()
- for name, exe in self.build.find_overrides.items():
- if cmd == exe:
- raise InterpreterException(f'Program {name!r} was overridden with the compiled executable {descr!r} and therefore cannot be used during configuration')
- raise InterpreterException(f'Program {descr!r} is a compiled executable and therefore cannot be used during configuration')
-
def run_command_impl(self,
- args: T.Tuple[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str, build.LocalProgram],
- T.List[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str, build.LocalProgram]]],
+ args: T.Tuple[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str],
+ T.List[T.Union[build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str]]],
kwargs: 'kwtypes.RunCommand',
in_builddir: bool = False) -> RunProcess:
cmd, cargs = args
@@ -805,17 +799,19 @@ class Interpreter(InterpreterBase, HoldableObject):
mlog.warning(implicit_check_false_warning, once=True)
check = False
+ overridden_msg = ('Program {!r} was overridden with the compiled '
+ 'executable {!r} and therefore cannot be used during '
+ 'configuration')
expanded_args: T.List[str] = []
- if isinstance(cmd, build.LocalProgram):
- prog = cmd.run_program()
- if prog is None:
- self._compiled_exe_error(cmd)
- for f in cmd.depend_files:
- self.add_build_def_file(f)
- cmd = prog
- elif isinstance(cmd, build.Executable):
- self._compiled_exe_error(cmd)
- elif isinstance(cmd, ExternalProgram):
+ if isinstance(cmd, build.Executable):
+ for name, exe in self.build.find_overrides.items():
+ if cmd == exe:
+ progname = name
+ break
+ else:
+ raise InterpreterException(f'Program {cmd.description()!r} is a compiled executable and therefore cannot be used during configuration')
+ raise InterpreterException(overridden_msg.format(progname, cmd.description()))
+ if isinstance(cmd, ExternalProgram):
if not cmd.found():
raise InterpreterException(f'command {cmd.get_name()!r} not found or not executable')
elif isinstance(cmd, compilers.Compiler):
@@ -847,15 +843,8 @@ class Interpreter(InterpreterBase, HoldableObject):
if not prog.found():
raise InterpreterException(f'Program {cmd!r} not found or not executable')
expanded_args.append(prog.get_path())
- elif isinstance(a, build.LocalProgram):
- prog = a.run_program()
- if prog is None:
- self._compiled_exe_error(a)
- for f in a.depend_files:
- self.add_build_def_file(f)
- expanded_args.append(prog.get_path())
else:
- self._compiled_exe_error(a)
+ raise InterpreterException(overridden_msg.format(a.name, cmd.description()))
# If any file that was used as an argument to the command
# changes, we must re-run the configuration step.
@@ -1620,7 +1609,7 @@ class Interpreter(InterpreterBase, HoldableObject):
def program_from_overrides(self, command_names: T.List[mesonlib.FileOrString],
extra_info: T.List['mlog.TV_Loggable']
- ) -> T.Optional[T.Union[ExternalProgram, build.LocalProgram]]:
+ ) -> T.Optional[T.Union[ExternalProgram, OverrideProgram, build.OverrideExecutable]]:
for name in command_names:
if not isinstance(name, str):
continue
@@ -1635,7 +1624,7 @@ class Interpreter(InterpreterBase, HoldableObject):
if isinstance(name, str):
self.build.searched_programs.add(name)
- def add_find_program_override(self, name: str, exe: T.Union[ExternalProgram, build.LocalProgram]) -> None:
+ def add_find_program_override(self, name: str, exe: T.Union[build.OverrideExecutable, ExternalProgram, 'OverrideProgram']) -> None:
if name in self.build.searched_programs:
raise InterpreterException(f'Tried to override finding of executable "{name}" which has already been found.')
if name in self.build.find_overrides:
@@ -1660,7 +1649,7 @@ class Interpreter(InterpreterBase, HoldableObject):
search_dirs: T.Optional[T.List[str]] = None,
version_arg: T.Optional[str] = '',
version_func: T.Optional[ProgramVersionFunc] = None
- ) -> T.Union[ExternalProgram, build.LocalProgram]:
+ ) -> T.Union['ExternalProgram', 'build.OverrideExecutable', 'OverrideProgram']:
args = mesonlib.listify(args)
extra_info: T.List[mlog.TV_Loggable] = []
@@ -1692,7 +1681,7 @@ class Interpreter(InterpreterBase, HoldableObject):
version_arg: T.Optional[str],
version_func: T.Optional[ProgramVersionFunc],
extra_info: T.List[mlog.TV_Loggable]
- ) -> T.Optional[T.Union[ExternalProgram, build.LocalProgram]]:
+ ) -> T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]]:
progobj = self.program_from_overrides(args, extra_info)
if progobj:
return progobj
@@ -1728,7 +1717,7 @@ class Interpreter(InterpreterBase, HoldableObject):
return progobj
- def check_program_version(self, progobj: T.Union[ExternalProgram, build.LocalProgram],
+ def check_program_version(self, progobj: T.Union[ExternalProgram, build.Executable, OverrideProgram],
wanted: T.Union[str, T.List[str]],
version_func: T.Optional[ProgramVersionFunc],
extra_info: T.List[mlog.TV_Loggable]) -> bool:
@@ -1755,7 +1744,7 @@ class Interpreter(InterpreterBase, HoldableObject):
def find_program_fallback(self, fallback: str, args: T.List[mesonlib.FileOrString],
default_options: OptionDict,
required: bool, extra_info: T.List[mlog.TV_Loggable]
- ) -> T.Optional[T.Union[ExternalProgram, build.LocalProgram]]:
+ ) -> T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]]:
mlog.log('Fallback to subproject', mlog.bold(fallback), 'which provides program',
mlog.bold(' '.join(args)))
sp_kwargs: kwtypes.DoSubproject = {
@@ -1782,7 +1771,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@disablerIfNotFound
def func_find_program(self, node: mparser.BaseNode, args: T.Tuple[T.List[mesonlib.FileOrString]],
kwargs: 'kwtypes.FindProgram',
- ) -> T.Union[ExternalProgram, build.LocalProgram]:
+ ) -> T.Union['build.Executable', ExternalProgram, 'OverrideProgram']:
disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
if disabled:
assert feature, 'for mypy'
@@ -1795,44 +1784,6 @@ class Interpreter(InterpreterBase, HoldableObject):
silent=False, wanted=kwargs['version'], version_arg=kwargs['version_argument'],
search_dirs=search_dirs)
- @FeatureNew('local_program', '1.10.0')
- @typed_pos_args('local_program', (str, mesonlib.File, build.Executable, build.CustomTarget, build.CustomTargetIndex))
- @typed_kwargs(
- 'local_program',
- DEPENDS_KW,
- DEPEND_FILES_KW,
- KwargInfo('interpreter', (ExternalProgram, NoneType), default=None),
- )
- def func_local_program(self, node: mparser.BaseNode, args: T.Tuple[T.Union[mesonlib.FileOrString, build.Executable, build.CustomTarget, build.CustomTargetIndex]],
- kwargs: kwtypes.LocalProgram) -> build.LocalProgram:
- return self._local_program_impl(args[0], kwargs['depends'], kwargs['depend_files'], kwargs['interpreter'])
-
- def _local_program_impl(self, exe: T.Union[mesonlib.FileOrString, build.Executable, build.CustomTarget, build.CustomTargetIndex],
- depends_: T.Optional[T.List[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]]] = None,
- depend_files_: T.Optional[T.List[mesonlib.FileOrString]] = None,
- interpreter: T.Optional[ExternalProgram] = None) -> build.LocalProgram:
- if isinstance(exe, build.CustomTarget):
- if len(exe.outputs) != 1:
- raise InvalidArguments('CustomTarget used as LocalProgram must have exactly one output.')
- depends = [d.target if isinstance(d, build.CustomTargetIndex) else d for d in (depends_ or [])]
- depend_files = self.source_strings_to_files(depend_files_ or [])
- if isinstance(exe, (str, mesonlib.File)):
- file = self.source_strings_to_files([exe])[0]
- abspath = file.absolute_path(self.environment.source_dir, self.environment.build_dir)
- prog = ExternalProgram(file.fname, command=[abspath], silent=True)
- return build.LocalProgram(prog, self.project_version, depends, depend_files)
- if interpreter:
- if not isinstance(exe, (build.CustomTarget, build.CustomTargetIndex)):
- raise InvalidArguments('The "interpreter" argument can only be used when the first argument is a custom target.')
- if not interpreter.found():
- raise InvalidArguments(f'Specified interpreter program {interpreter.description()!r} not found.')
- target = exe.target if isinstance(exe, build.CustomTargetIndex) else exe
- depends.append(target)
- cmd = interpreter.get_command() + [self.backend.get_target_filename(exe)]
- prog = ExternalProgram(exe.name, command=cmd, silent=True)
- return build.LocalProgram(prog, self.project_version, depends, depend_files)
- return build.LocalProgram(exe, self.project_version, depends, depend_files)
-
# When adding kwargs, please check if they make sense in dependencies.get_dep_identifier()
@FeatureNewKwargs('dependency', '0.57.0', ['cmake_package_version'])
@FeatureNewKwargs('dependency', '0.56.0', ['allow_fallback'])
@@ -2255,7 +2206,7 @@ class Interpreter(InterpreterBase, HoldableObject):
self.add_target(name, tg)
return tg
- @typed_pos_args('generator', (build.Executable, ExternalProgram, build.LocalProgram))
+ @typed_pos_args('generator', (build.Executable, ExternalProgram))
@typed_kwargs(
'generator',
KwargInfo('arguments', ContainerTypeInfo(list, str, allow_empty=False), required=True, listify=True),
@@ -2265,7 +2216,7 @@ class Interpreter(InterpreterBase, HoldableObject):
KwargInfo('capture', bool, default=False, since='0.43.0'),
)
def func_generator(self, node: mparser.FunctionNode,
- args: T.Tuple[T.Union[build.Executable, ExternalProgram, build.LocalProgram]],
+ args: T.Tuple[T.Union[build.Executable, ExternalProgram]],
kwargs: 'kwtypes.FuncGenerator') -> build.Generator:
for rule in kwargs['output']:
if '@BASENAME@' not in rule and '@PLAINNAME@' not in rule:
@@ -2279,17 +2230,17 @@ class Interpreter(InterpreterBase, HoldableObject):
return build.Generator(args[0], **kwargs)
- @typed_pos_args('benchmark', str, (build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.LocalProgram))
+ @typed_pos_args('benchmark', str, (build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex))
@typed_kwargs('benchmark', *TEST_KWS)
def func_benchmark(self, node: mparser.BaseNode,
- args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.LocalProgram]],
+ args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File]],
kwargs: 'kwtypes.FuncBenchmark') -> None:
self.add_test(node, args, kwargs, False)
- @typed_pos_args('test', str, (build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.LocalProgram))
+ @typed_pos_args('test', str, (build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex))
@typed_kwargs('test', *TEST_KWS, KwargInfo('is_parallel', bool, default=True))
def func_test(self, node: mparser.BaseNode,
- args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.LocalProgram]],
+ args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex]],
kwargs: 'kwtypes.FuncTest') -> None:
self.add_test(node, args, kwargs, True)
@@ -2303,7 +2254,7 @@ class Interpreter(InterpreterBase, HoldableObject):
return ENV_KW.convertor(envlist)
def make_test(self, node: mparser.BaseNode,
- args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.LocalProgram]],
+ args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File, build.CustomTarget, build.CustomTargetIndex]],
kwargs: 'kwtypes.BaseTest',
klass: T.Type[TestClass] = Test) -> TestClass:
name = args[0]
@@ -2312,20 +2263,15 @@ class Interpreter(InterpreterBase, HoldableObject):
location=node)
name = name.replace(':', '_')
exe = args[1]
- depends = list(kwargs['depends'] or [])
- if isinstance(exe, build.LocalProgram):
- # FIXME: tests does not have depend_files?
- depends.extend(exe.depends)
- exe = exe.program
- elif isinstance(exe, ExternalProgram):
+ if isinstance(exe, ExternalProgram):
if not exe.found():
raise InvalidArguments('Tried to use not-found external program as test exe')
elif isinstance(exe, mesonlib.File):
exe = self.find_program_impl([exe])
elif isinstance(exe, build.CustomTarget):
- depends.append(exe)
+ kwargs.setdefault('depends', []).append(exe)
elif isinstance(exe, build.CustomTargetIndex):
- depends.append(exe.target)
+ kwargs.setdefault('depends', []).append(exe.target)
env = self.unpack_env_kwarg(kwargs)
@@ -2344,7 +2290,7 @@ class Interpreter(InterpreterBase, HoldableObject):
prj,
suite,
exe,
- depends,
+ kwargs['depends'],
kwargs.get('is_parallel', False),
kwargs['args'],
env,
@@ -2669,7 +2615,7 @@ class Interpreter(InterpreterBase, HoldableObject):
KwargInfo('capture', bool, default=False, since='0.41.0'),
KwargInfo(
'command',
- (ContainerTypeInfo(list, (build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str, build.LocalProgram), allow_empty=False), NoneType),
+ (ContainerTypeInfo(list, (build.Executable, ExternalProgram, compilers.Compiler, mesonlib.File, str), allow_empty=False), NoneType),
listify=True,
),
KwargInfo(