summaryrefslogtreecommitdiff
path: root/mesonbuild/interpreter
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
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')
-rw-r--r--mesonbuild/interpreter/__init__.py4
-rw-r--r--mesonbuild/interpreter/interpreter.py140
-rw-r--r--mesonbuild/interpreter/interpreterobjects.py28
-rw-r--r--mesonbuild/interpreter/kwargs.py12
-rw-r--r--mesonbuild/interpreter/mesonmain.py40
-rw-r--r--mesonbuild/interpreter/type_checking.py7
6 files changed, 91 insertions, 140 deletions
diff --git a/mesonbuild/interpreter/__init__.py b/mesonbuild/interpreter/__init__.py
index 5186b842b..e2ccce479 100644
--- a/mesonbuild/interpreter/__init__.py
+++ b/mesonbuild/interpreter/__init__.py
@@ -20,6 +20,7 @@ __all__ = [
'SubprojectHolder',
'DependencyHolder',
'GeneratedListHolder',
+ 'ExternalProgramHolder',
'extract_required_kwarg',
'ArrayHolder',
@@ -34,7 +35,8 @@ from .compiler import CompilerHolder
from .interpreterobjects import (ExecutableHolder, BuildTargetHolder, CustomTargetHolder,
CustomTargetIndexHolder, MachineHolder, Test,
ConfigurationDataHolder, SubprojectHolder, DependencyHolder,
- GeneratedListHolder, extract_required_kwarg)
+ GeneratedListHolder, ExternalProgramHolder,
+ extract_required_kwarg)
from .primitives import (
ArrayHolder,
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(
diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py
index addc7d3db..86e8957bc 100644
--- a/mesonbuild/interpreter/interpreterobjects.py
+++ b/mesonbuild/interpreter/interpreterobjects.py
@@ -23,7 +23,7 @@ from ..interpreterbase import (
flatten, resolve_second_level_holders, InterpreterException, InvalidArguments, InvalidCode)
from ..interpreter.type_checking import NoneType, ENV_KW, ENV_SEPARATOR_KW, PKGCONFIG_DEFINE_KW
from ..dependencies import Dependency, ExternalLibrary, InternalDependency
-from ..programs import ExternalProgram, BaseProgram
+from ..programs import ExternalProgram
from ..mesonlib import HoldableObject, listify, Popen_safe
import typing as T
@@ -605,10 +605,10 @@ class DependencyHolder(ObjectHolder[Dependency]):
raise InterpreterException('as_shared method is only supported on declare_dependency() objects')
return self.held_object.get_as_shared(kwargs['recursive'])
-_BASEPROG = T.TypeVar('_BASEPROG', bound=BaseProgram)
+_EXTPROG = T.TypeVar('_EXTPROG', bound=ExternalProgram)
-class BaseProgramHolder(ObjectHolder[_BASEPROG]):
- def __init__(self, ep: _BASEPROG, interpreter: 'Interpreter') -> None:
+class _ExternalProgramHolder(ObjectHolder[_EXTPROG]):
+ def __init__(self, ep: _EXTPROG, interpreter: 'Interpreter') -> None:
super().__init__(ep, interpreter)
@noPosargs
@@ -619,15 +619,15 @@ class BaseProgramHolder(ObjectHolder[_BASEPROG]):
@noPosargs
@noKwargs
- @FeatureDeprecated('Program.path', '0.55.0',
- 'use Program.full_path() instead')
+ @FeatureDeprecated('ExternalProgram.path', '0.55.0',
+ 'use ExternalProgram.full_path() instead')
@InterpreterObject.method('path')
def path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self._full_path()
@noPosargs
@noKwargs
- @FeatureNew('Program.full_path', '0.55.0')
+ @FeatureNew('ExternalProgram.full_path', '0.55.0')
@InterpreterObject.method('full_path')
def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self._full_path()
@@ -641,11 +641,9 @@ class BaseProgramHolder(ObjectHolder[_BASEPROG]):
@noPosargs
@noKwargs
- @FeatureNew('Program.version', '0.62.0')
+ @FeatureNew('ExternalProgram.version', '0.62.0')
@InterpreterObject.method('version')
def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
- if isinstance(self.held_object, build.LocalProgram) and isinstance(self.held_object.program, build.Executable):
- FeatureNew.single_use('Program.version with an executable', '1.9.0', subproject=self.subproject, location=self.current_node)
if not self.found():
raise InterpreterException('Unable to get the version of a not-found external program')
try:
@@ -656,6 +654,8 @@ class BaseProgramHolder(ObjectHolder[_BASEPROG]):
def found(self) -> bool:
return self.held_object.found()
+class ExternalProgramHolder(_ExternalProgramHolder[ExternalProgram]):
+ pass
class ExternalLibraryHolder(ObjectHolder[ExternalLibrary]):
def __init__(self, el: ExternalLibrary, interpreter: 'Interpreter'):
@@ -1163,3 +1163,11 @@ class StructuredSourcesHolder(ObjectHolder[build.StructuredSources]):
def __init__(self, sources: build.StructuredSources, interp: 'Interpreter'):
super().__init__(sources, interp)
+
+class OverrideExecutableHolder(BuildTargetHolder[build.OverrideExecutable]):
+ @noPosargs
+ @noKwargs
+ @FeatureNew('OverrideExecutable.version', '1.9.0')
+ @InterpreterObject.method('version')
+ def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
+ return self.held_object.get_version(self.interpreter)
diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py
index 22dde255d..e95d47341 100644
--- a/mesonbuild/interpreter/kwargs.py
+++ b/mesonbuild/interpreter/kwargs.py
@@ -171,8 +171,7 @@ class FuncAddLanguages(ExtractRequired):
class RunTarget(TypedDict):
- command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget, ExternalProgram,
- File, LocalProgram]]
+ command: T.List[T.Union[str, build.BuildTarget, build.CustomTarget, ExternalProgram, File]]
depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
env: EnvironmentVariables
@@ -183,7 +182,7 @@ class CustomTarget(TypedDict):
build_always_stale: T.Optional[bool]
build_by_default: T.Optional[bool]
capture: bool
- command: T.List[T.Union[str, build.BuildTargetTypes, ExternalProgram, File, LocalProgram]]
+ command: T.List[T.Union[str, build.BuildTargetTypes, ExternalProgram, File]]
console: bool
depend_files: T.List[FileOrString]
depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
@@ -247,13 +246,6 @@ class FindProgram(ExtractRequired, ExtractSearchDirs):
version: T.List[str]
-class LocalProgram(TypedDict):
-
- depend_files: T.List[FileOrString]
- depends: T.List[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]]
- interpreter: T.Optional[ExternalProgram]
-
-
class RunCommand(TypedDict):
check: bool
diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py
index 3afeb8647..d22d36bf0 100644
--- a/mesonbuild/interpreter/mesonmain.py
+++ b/mesonbuild/interpreter/mesonmain.py
@@ -14,7 +14,7 @@ from .. import mlog, coredata
from ..mesonlib import MachineChoice
from ..options import OptionKey
-from ..programs import ExternalProgram
+from ..programs import OverrideProgram, ExternalProgram
from ..interpreter.type_checking import ENV_KW, ENV_METHOD_KW, ENV_SEPARATOR_KW, env_convertor_with_method
from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated,
typed_pos_args, noArgsFlattening, noPosargs, noKwargs,
@@ -57,23 +57,21 @@ class MesonMain(MesonInterpreterObject):
self.interpreter = interpreter
def _find_source_script(
- self, name: str, prog: T.Union[str, mesonlib.File, build.Executable, ExternalProgram, build.LocalProgram],
- args: T.List[str], allow_built_program: bool = False) -> 'ExecutableSerialisation':
- largs: T.List[T.Union[str, build.Executable, ExternalProgram, build.LocalProgram]] = []
+ self, name: str, prog: T.Union[str, mesonlib.File, build.Executable, ExternalProgram],
+ args: T.List[str]) -> 'ExecutableSerialisation':
+ largs: T.List[T.Union[str, build.Executable, ExternalProgram]] = []
if isinstance(prog, (build.Executable, ExternalProgram)):
FeatureNew.single_use(f'Passing executable/found program object to script parameter of {name}',
'0.55.0', self.subproject, location=self.current_node)
- elif isinstance(prog, (str, mesonlib.File)):
+ largs.append(prog)
+ else:
if isinstance(prog, mesonlib.File):
FeatureNew.single_use(f'Passing file object to script parameter of {name}',
'0.57.0', self.subproject, location=self.current_node)
- prog = self.interpreter.find_program_impl([prog])
-
- if isinstance(prog, build.LocalProgram) and not allow_built_program and not prog.run_program():
- self.interpreter._compiled_exe_error(prog)
+ found = self.interpreter.find_program_impl([prog])
+ largs.append(found)
- largs.append(prog)
largs.extend(args)
es = self.interpreter.backend.get_executable_serialisation(largs, verbose=True)
es.subproject = self.interpreter.subproject
@@ -118,7 +116,7 @@ class MesonMain(MesonInterpreterObject):
@typed_pos_args(
'meson.add_install_script',
- (str, mesonlib.File, build.Executable, ExternalProgram, build.LocalProgram),
+ (str, mesonlib.File, build.Executable, ExternalProgram),
varargs=(str, mesonlib.File, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex, ExternalProgram)
)
@typed_kwargs(
@@ -134,7 +132,7 @@ class MesonMain(MesonInterpreterObject):
T.List[T.Union[str, mesonlib.File, build.BuildTargetTypes, ExternalProgram]]],
kwargs: 'AddInstallScriptKW') -> None:
script_args = self._process_script_args('add_install_script', args[1])
- script = self._find_source_script('add_install_script', args[0], script_args, allow_built_program=True)
+ script = self._find_source_script('add_install_script', args[0], script_args)
script.skip_if_destdir = kwargs['skip_if_destdir']
script.tag = kwargs['install_tag']
script.dry_run = kwargs['dry_run']
@@ -149,7 +147,7 @@ class MesonMain(MesonInterpreterObject):
@InterpreterObject.method('add_postconf_script')
def add_postconf_script_method(
self,
- args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram, build.LocalProgram],
+ args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram],
T.List[T.Union[str, mesonlib.File, ExternalProgram]]],
kwargs: 'TYPE_kwargs') -> None:
script_args = self._process_script_args('add_postconf_script', args[1])
@@ -166,7 +164,7 @@ class MesonMain(MesonInterpreterObject):
@InterpreterObject.method('add_dist_script')
def add_dist_script_method(
self,
- args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram, build.LocalProgram],
+ args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram],
T.List[T.Union[str, mesonlib.File, ExternalProgram]]],
kwargs: 'TYPE_kwargs') -> None:
if args[1]:
@@ -314,13 +312,19 @@ class MesonMain(MesonInterpreterObject):
self.build.dep_manifest_name = args[0]
@FeatureNew('meson.override_find_program', '0.46.0')
- @typed_pos_args('meson.override_find_program', str, (mesonlib.File, ExternalProgram, build.Executable, build.LocalProgram))
+ @typed_pos_args('meson.override_find_program', str, (mesonlib.File, ExternalProgram, build.Executable))
@noKwargs
@InterpreterObject.method('override_find_program')
- def override_find_program_method(self, args: T.Tuple[str, T.Union[mesonlib.File, ExternalProgram, build.Executable, build.LocalProgram]], kwargs: 'TYPE_kwargs') -> None:
+ def override_find_program_method(self, args: T.Tuple[str, T.Union[mesonlib.File, ExternalProgram, build.Executable]], kwargs: 'TYPE_kwargs') -> None:
name, exe = args
- if not isinstance(exe, (ExternalProgram, build.LocalProgram)):
- exe = self.interpreter._local_program_impl(exe)
+ if isinstance(exe, mesonlib.File):
+ abspath = exe.absolute_path(self.interpreter.environment.source_dir,
+ self.interpreter.environment.build_dir)
+ if not os.path.exists(abspath):
+ raise InterpreterException(f'Tried to override {name} with a file that does not exist.')
+ exe = OverrideProgram(name, self.interpreter.project_version, command=[abspath])
+ elif isinstance(exe, build.Executable):
+ exe = build.OverrideExecutable(exe, self.interpreter.project_version)
self.interpreter.add_find_program_override(name, exe)
@typed_kwargs(
diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py
index a54a69ff0..4f961bb60 100644
--- a/mesonbuild/interpreter/type_checking.py
+++ b/mesonbuild/interpreter/type_checking.py
@@ -10,8 +10,7 @@ import typing as T
from .. import compilers
from ..build import (CustomTarget, BuildTarget,
CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs,
- BothLibraries, SharedLibrary, StaticLibrary, Jar, Executable, StructuredSources,
- LocalProgram)
+ BothLibraries, SharedLibrary, StaticLibrary, Jar, Executable, StructuredSources)
from ..options import OptionKey, UserFeatureOption
from ..dependencies import Dependency, InternalDependency
from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo, FeatureBroken
@@ -286,9 +285,9 @@ DEPEND_FILES_KW: KwargInfo[T.List[T.Union[str, File]]] = KwargInfo(
default=[],
)
-COMMAND_KW: KwargInfo[T.List[T.Union[str, BuildTargetTypes, ExternalProgram, File, LocalProgram]]] = KwargInfo(
+COMMAND_KW: KwargInfo[T.List[T.Union[str, BuildTargetTypes, ExternalProgram, File]]] = KwargInfo(
'command',
- ContainerTypeInfo(list, (str, BuildTarget, CustomTarget, CustomTargetIndex, ExternalProgram, File, LocalProgram), allow_empty=False),
+ ContainerTypeInfo(list, (str, BuildTarget, CustomTarget, CustomTargetIndex, ExternalProgram, File), allow_empty=False),
required=True,
listify=True,
default=[],