diff options
author | Dylan Baker <dylan@pnwbakers.com> | 2022-07-14 12:59:48 -0700 |
---|---|---|
committer | Eli Schwartz <eschwartz93@gmail.com> | 2022-08-17 16:25:36 -0400 |
commit | 6843f56f6b8e71e75c287de31686913eea5e4a44 (patch) | |
tree | a92e933d88d48dd2bfd4a1fc2bb652296f053332 /mesonbuild | |
parent | 2801ead6d3a144f3cf7ae03f61bb463c7aeac0a9 (diff) | |
download | meson-6843f56f6b8e71e75c287de31686913eea5e4a44.zip meson-6843f56f6b8e71e75c287de31686913eea5e4a44.tar.gz meson-6843f56f6b8e71e75c287de31686913eea5e4a44.tar.bz2 |
modules: use module level information about new and deprecation
Instead of using FeatureNew/FeatureDeprecated in the module.
The goal here is to be able to handle information about modules in a
single place, instead of having to handle it separately. Each module
simply defines some metadata, and then the interpreter handles the rest.
Diffstat (limited to 'mesonbuild')
25 files changed, 114 insertions, 54 deletions
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index c897494..fef8f4b 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -599,7 +599,7 @@ class Interpreter(InterpreterBase, HoldableObject): dep = df.lookup(kwargs, force_fallback=True) self.build.stdlibs[for_machine][l] = dep - def _import_module(self, modname: str, required: bool) -> NewExtensionModule: + def _import_module(self, modname: str, required: bool, node: mparser.BaseNode) -> NewExtensionModule: if modname in self.modules: return self.modules[modname] try: @@ -607,11 +607,15 @@ class Interpreter(InterpreterBase, HoldableObject): except ImportError: if required: raise InvalidArguments(f'Module "{modname}" does not exist') - ext_module = NotFoundExtensionModule() + ext_module = NotFoundExtensionModule(modname) else: ext_module = module.initialize(self) assert isinstance(ext_module, (ExtensionModule, NewExtensionModule)) self.build.modules.append(modname) + if ext_module.INFO.added: + FeatureNew.single_use(f'module {ext_module.INFO.name}', ext_module.INFO.added, self.subproject, location=node) + if ext_module.INFO.deprecated: + FeatureDeprecated.single_use(f'module {ext_module.INFO.name}', ext_module.INFO.deprecated, self.subproject, location=node) self.modules[modname] = ext_module return ext_module @@ -627,20 +631,19 @@ class Interpreter(InterpreterBase, HoldableObject): modname = args[0] disabled, required, _ = extract_required_kwarg(kwargs, self.subproject) if disabled: - return NotFoundExtensionModule() + return NotFoundExtensionModule(modname) if modname.startswith('unstable-'): plainname = modname.split('-', 1)[1] try: # check if stable module exists - mod = self._import_module(plainname, required) - # XXX: this is actually not helpful, since it doesn't do a version check + mod = self._import_module(plainname, required, node) mlog.warning(f'Module {modname} is now stable, please use the {plainname} module instead.') return mod except InvalidArguments: mlog.warning(f'Module {modname} has no backwards or forwards compatibility and might not exist in future releases.', location=node) modname = 'unstable_' + plainname - return self._import_module(modname, required) + return self._import_module(modname, required, node) @typed_pos_args('files', varargs=str) @noKwargs diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 56370d1..0681940 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -15,6 +15,7 @@ # This file contains the base representation for import('modname') from __future__ import annotations +import dataclasses import typing as T from .. import mesonlib @@ -163,6 +164,17 @@ class ModuleObject(HoldableObject): class MutableModuleObject(ModuleObject): pass + +@dataclasses.dataclass +class ModuleInfo: + + """Metadata about a Module.""" + + name: str + added: T.Optional[str] = None + deprecated: T.Optional[str] = None + + class NewExtensionModule(ModuleObject): """Class for modern modules @@ -170,6 +182,8 @@ class NewExtensionModule(ModuleObject): provides the found method. """ + INFO: ModuleInfo + def __init__(self) -> None: super().__init__() self.methods.update({ @@ -203,6 +217,10 @@ class NotFoundExtensionModule(NewExtensionModule): provides the found method. """ + def __init__(self, name: str) -> None: + super().__init__() + self.INFO = ModuleInfo(name) + @staticmethod def found() -> bool: return False diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 1950254..326aac6 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -18,7 +18,7 @@ import os, os.path, pathlib import shutil import typing as T -from . import ExtensionModule, ModuleReturnValue, ModuleObject +from . import ExtensionModule, ModuleReturnValue, ModuleObject, ModuleInfo from .. import build, mesonlib, mlog, dependencies from ..cmake import TargetOptions, cmake_defines_to_args @@ -247,7 +247,8 @@ class CmakeModule(ExtensionModule): cmake_detected = False cmake_root = None - @FeatureNew('CMake Module', '0.50.0') + INFO = ModuleInfo('cmake', '0.50.0') + def __init__(self, interpreter): super().__init__(interpreter) self.methods.update({ diff --git a/mesonbuild/modules/dlang.py b/mesonbuild/modules/dlang.py index d9255d9..7a9b99f 100644 --- a/mesonbuild/modules/dlang.py +++ b/mesonbuild/modules/dlang.py @@ -18,17 +18,18 @@ import json import os -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from .. import dependencies from .. import mlog -from ..interpreterbase import FeatureNew, typed_pos_args +from ..interpreterbase import typed_pos_args from ..mesonlib import Popen_safe, MesonException class DlangModule(ExtensionModule): class_dubbin = None init_dub = False - @FeatureNew('Dlang Module', '0.48.0') + INFO = ModuleInfo('dlang', '0.48.0') + def __init__(self, interpreter): super().__init__(interpreter) self.methods.update({ diff --git a/mesonbuild/modules/fs.py b/mesonbuild/modules/fs.py index d0f5e2e..f0e3f4c 100644 --- a/mesonbuild/modules/fs.py +++ b/mesonbuild/modules/fs.py @@ -18,7 +18,7 @@ import os from pathlib import Path, PurePath, PureWindowsPath from .. import mlog -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from ..mesonlib import ( File, MesonException, @@ -41,7 +41,8 @@ if T.TYPE_CHECKING: class FSModule(ExtensionModule): - @FeatureNew('Fs Module', '0.53.0') + INFO = ModuleInfo('fs', '0.53.0') + def __init__(self, interpreter: 'Interpreter') -> None: super().__init__(interpreter) self.methods.update({ diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 230783a..1c21cce 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -24,7 +24,7 @@ import subprocess import textwrap import typing as T -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from . import ModuleReturnValue from .. import build from .. import interpreter @@ -272,6 +272,9 @@ gresource_dep_needed_version = '>= 2.51.1' native_glib_version: T.Optional[str] = None class GnomeModule(ExtensionModule): + + INFO = ModuleInfo('gnome') + def __init__(self, interpreter: 'Interpreter') -> None: super().__init__(interpreter) self.gir_dep: T.Optional[Dependency] = None diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index beb92b8..b354d17 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -20,10 +20,10 @@ from collections import OrderedDict from mesonbuild import mesonlib from mesonbuild import mlog, build from mesonbuild.coredata import MesonException -from . import ModuleReturnValue +from . import ModuleReturnValue, ModuleInfo from . import ExtensionModule from ..dependencies import Dependency, InternalDependency -from ..interpreterbase import FeatureNew, InvalidArguments, noPosargs, noKwargs, typed_pos_args +from ..interpreterbase import InvalidArguments, noPosargs, noKwargs, typed_pos_args from ..interpreter import CustomTargetHolder from ..programs import ExternalProgram @@ -38,6 +38,7 @@ MIN_HOTDOC_VERSION = '0.8.100' class HotdocTargetBuilder: + def __init__(self, name, state, hotdoc, interpreter, kwargs): self.hotdoc = hotdoc self.build_by_default = kwargs.pop('build_by_default', False) @@ -396,7 +397,9 @@ class HotdocTarget(build.CustomTarget): class HotDocModule(ExtensionModule): - @FeatureNew('Hotdoc Module', '0.48.0') + + INFO = ModuleInfo('hotdoc', '0.48.0') + def __init__(self, interpreter): super().__init__(interpreter) self.hotdoc = ExternalProgram('hotdoc') diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index f5eec96..2af1198 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -16,7 +16,7 @@ from __future__ import annotations from os import path import typing as T -from . import ExtensionModule, ModuleReturnValue +from . import ExtensionModule, ModuleReturnValue, ModuleInfo from .. import build from .. import mesonlib from .. import mlog @@ -124,6 +124,9 @@ PRESET_ARGS = { class I18nModule(ExtensionModule): + + INFO = ModuleInfo('i18n') + def __init__(self, interpreter: 'Interpreter'): super().__init__(interpreter) self.methods.update({ diff --git a/mesonbuild/modules/java.py b/mesonbuild/modules/java.py index a8e5062..a48750a 100644 --- a/mesonbuild/modules/java.py +++ b/mesonbuild/modules/java.py @@ -22,7 +22,7 @@ from mesonbuild.build import CustomTarget, CustomTargetIndex, GeneratedList, Tar from mesonbuild.compilers import detect_compiler_for from mesonbuild.interpreterbase.decorators import ContainerTypeInfo, FeatureDeprecated, FeatureNew, KwargInfo, typed_pos_args, typed_kwargs from mesonbuild.mesonlib import version_compare, MachineChoice -from . import NewExtensionModule, ModuleReturnValue +from . import NewExtensionModule, ModuleReturnValue, ModuleInfo if T.TYPE_CHECKING: from . import ModuleState @@ -30,7 +30,9 @@ if T.TYPE_CHECKING: from ..interpreter import Interpreter class JavaModule(NewExtensionModule): - @FeatureNew('Java Module', '0.60.0') + + INFO = ModuleInfo('java', '0.60.0') + def __init__(self, interpreter: Interpreter): super().__init__() self.methods.update({ diff --git a/mesonbuild/modules/keyval.py b/mesonbuild/modules/keyval.py index 36daea8..94db567 100644 --- a/mesonbuild/modules/keyval.py +++ b/mesonbuild/modules/keyval.py @@ -15,9 +15,9 @@ import os import typing as T -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from .. import mesonlib -from ..interpreterbase import FeatureNew, noKwargs, typed_pos_args +from ..interpreterbase import noKwargs, typed_pos_args if T.TYPE_CHECKING: from ..interpreter import Interpreter @@ -25,7 +25,8 @@ if T.TYPE_CHECKING: class KeyvalModule(ExtensionModule): - @FeatureNew('Keyval Module', '0.55.0') + INFO = ModuleInfo('keyval', '0.55.0') + def __init__(self, interp: 'Interpreter'): super().__init__(interp) self.methods.update({ diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py index e36899f..15f8237 100644 --- a/mesonbuild/modules/modtest.py +++ b/mesonbuild/modules/modtest.py @@ -15,7 +15,7 @@ from __future__ import annotations import typing as T -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from ..interpreterbase import noKwargs, noPosargs if T.TYPE_CHECKING: @@ -25,6 +25,9 @@ if T.TYPE_CHECKING: class TestModule(ExtensionModule): + + INFO = ModuleInfo('modtest') + def __init__(self, interpreter: Interpreter) -> None: super().__init__(interpreter) self.methods.update({ diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 830341c..394b480 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -16,7 +16,7 @@ from pathlib import PurePath import os import typing as T -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from . import ModuleReturnValue from .. import build from .. import dependencies @@ -276,6 +276,9 @@ class DependenciesHelper: self.cflags = _fn(self.cflags) class PkgConfigModule(ExtensionModule): + + INFO = ModuleInfo('pkgconfig') + def __init__(self, interpreter): super().__init__(interpreter) self.methods.update({ diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 5a6daa0..91443b8 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -20,7 +20,7 @@ import os import shutil import typing as T -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from .. import mesonlib from .. import mlog from ..coredata import UserFeatureOption @@ -663,7 +663,8 @@ class PythonInstallation(ExternalProgramHolder): class PythonModule(ExtensionModule): - @FeatureNew('Python Module', '0.46.0') + INFO = ModuleInfo('python', '0.46.0') + def __init__(self, interpreter: 'Interpreter') -> None: super().__init__(interpreter) self.installations: T.Dict[str, ExternalProgram] = {} diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py index 1e7463c..52f8531 100644 --- a/mesonbuild/modules/python3.py +++ b/mesonbuild/modules/python3.py @@ -15,15 +15,16 @@ import sysconfig from .. import mesonlib -from . import ExtensionModule -from ..interpreterbase import typed_pos_args, noPosargs, noKwargs, permittedKwargs, FeatureDeprecated, FeatureNew +from . import ExtensionModule, ModuleInfo +from ..interpreterbase import typed_pos_args, noPosargs, noKwargs, permittedKwargs from ..build import known_shmod_kwargs from ..programs import ExternalProgram class Python3Module(ExtensionModule): - @FeatureNew('python3 module', '0.38.0') - @FeatureDeprecated('python3 module', '0.48.0') + + INFO = ModuleInfo('python3', '0.38.0', deprecated='0.48.0') + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.methods.update({ diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index e85a150..b8948f7 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -13,10 +13,13 @@ # limitations under the License. from .qt import QtBaseModule +from . import ModuleInfo class Qt4Module(QtBaseModule): + INFO = ModuleInfo('qt4') + def __init__(self, interpreter): QtBaseModule.__init__(self, interpreter, qt_version=4) diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index 873c2db..3933ea0 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -13,10 +13,13 @@ # limitations under the License. from .qt import QtBaseModule +from . import ModuleInfo class Qt5Module(QtBaseModule): + INFO = ModuleInfo('qt5') + def __init__(self, interpreter): QtBaseModule.__init__(self, interpreter, qt_version=5) diff --git a/mesonbuild/modules/qt6.py b/mesonbuild/modules/qt6.py index 3cfe243..66fc43f 100644 --- a/mesonbuild/modules/qt6.py +++ b/mesonbuild/modules/qt6.py @@ -13,12 +13,13 @@ # limitations under the License. from .qt import QtBaseModule -from ..interpreterbase import FeatureNew +from . import ModuleInfo class Qt6Module(QtBaseModule): - @FeatureNew('Qt6 Module', '0.57.0') + INFO = ModuleInfo('qt6', '0.57.0') + def __init__(self, interpreter): QtBaseModule.__init__(self, interpreter, qt_version=6) diff --git a/mesonbuild/modules/sourceset.py b/mesonbuild/modules/sourceset.py index f091f6e..7bec2b7 100644 --- a/mesonbuild/modules/sourceset.py +++ b/mesonbuild/modules/sourceset.py @@ -15,7 +15,7 @@ from __future__ import annotations import typing as T -from . import ExtensionModule, ModuleObject, MutableModuleObject +from . import ExtensionModule, ModuleObject, MutableModuleObject, ModuleInfo from .. import build from .. import dependencies from .. import mesonlib @@ -289,7 +289,9 @@ class SourceFilesObject(ModuleObject): return list(self.files.deps) class SourceSetModule(ExtensionModule): - @FeatureNew('SourceSet module', '0.51.0') + + INFO = ModuleInfo('sourceset', '0.51.0') + def __init__(self, interpreter: Interpreter): super().__init__(interpreter) self.methods.update({ diff --git a/mesonbuild/modules/unstable_cuda.py b/mesonbuild/modules/unstable_cuda.py index 08dc016..e2340fc 100644 --- a/mesonbuild/modules/unstable_cuda.py +++ b/mesonbuild/modules/unstable_cuda.py @@ -19,11 +19,11 @@ import re from ..mesonlib import version_compare from ..compilers import CudaCompiler -from . import NewExtensionModule +from . import NewExtensionModule, ModuleInfo from ..interpreterbase import ( flatten, permittedKwargs, noKwargs, - InvalidArguments, FeatureNew + InvalidArguments ) if T.TYPE_CHECKING: @@ -32,7 +32,8 @@ if T.TYPE_CHECKING: class CudaModule(NewExtensionModule): - @FeatureNew('CUDA module', '0.50.0') + INFO = ModuleInfo('CUDA', '0.50.0') + def __init__(self, *args, **kwargs): super().__init__() self.methods.update({ diff --git a/mesonbuild/modules/unstable_external_project.py b/mesonbuild/modules/unstable_external_project.py index 82e51e8..74279a6 100644 --- a/mesonbuild/modules/unstable_external_project.py +++ b/mesonbuild/modules/unstable_external_project.py @@ -18,7 +18,7 @@ import shlex import subprocess import typing as T -from . import ExtensionModule, ModuleReturnValue, NewExtensionModule +from . import ExtensionModule, ModuleReturnValue, NewExtensionModule, ModuleInfo from .. import mlog, build from ..compilers.compilers import CFLAGS_MAPPING from ..envconfig import ENV_VAR_PROG_MAP @@ -273,7 +273,9 @@ class ExternalProject(NewExtensionModule): class ExternalProjectModule(ExtensionModule): - @FeatureNew('External build system Module', '0.56.0') + + INFO = ModuleInfo('External build system', '0.56.0') + def __init__(self, interpreter: 'Interpreter'): super().__init__(interpreter) self.methods.update({'add_project': self.add_project, diff --git a/mesonbuild/modules/unstable_icestorm.py b/mesonbuild/modules/unstable_icestorm.py index b4ddd5c..50809b9 100644 --- a/mesonbuild/modules/unstable_icestorm.py +++ b/mesonbuild/modules/unstable_icestorm.py @@ -16,11 +16,10 @@ from __future__ import annotations import itertools import typing as T -from . import ExtensionModule, ModuleReturnValue +from . import ExtensionModule, ModuleReturnValue, ModuleInfo from .. import build from .. import mesonlib from ..interpreter.type_checking import CT_INPUT_KW -from ..interpreterbase import FeatureNew from ..interpreterbase.decorators import KwargInfo, typed_kwargs, typed_pos_args if T.TYPE_CHECKING: @@ -37,7 +36,8 @@ if T.TYPE_CHECKING: class IceStormModule(ExtensionModule): - @FeatureNew('FPGA/Icestorm Module', '0.45.0') + INFO = ModuleInfo('FPGA/Icestorm', '0.45.0') + def __init__(self, interpreter: Interpreter) -> None: super().__init__(interpreter) self.tools: T.Dict[str, ExternalProgram] = {} diff --git a/mesonbuild/modules/unstable_rust.py b/mesonbuild/modules/unstable_rust.py index e31a697..cc0620d 100644 --- a/mesonbuild/modules/unstable_rust.py +++ b/mesonbuild/modules/unstable_rust.py @@ -15,12 +15,12 @@ import os import typing as T -from . import ExtensionModule, ModuleReturnValue +from . import ExtensionModule, ModuleReturnValue, ModuleInfo from .. import mlog from ..build import BothLibraries, BuildTarget, CustomTargetIndex, Executable, ExtractedObjects, GeneratedList, IncludeDirs, CustomTarget, StructuredSources from ..dependencies import Dependency, ExternalLibrary from ..interpreter.interpreter import TEST_KWARGS, OUTPUT_KW -from ..interpreterbase import ContainerTypeInfo, InterpreterException, KwargInfo, FeatureNew, typed_kwargs, typed_pos_args, noPosargs +from ..interpreterbase import ContainerTypeInfo, InterpreterException, KwargInfo, typed_kwargs, typed_pos_args, noPosargs from ..mesonlib import File if T.TYPE_CHECKING: @@ -50,7 +50,8 @@ class RustModule(ExtensionModule): """A module that holds helper functions for rust.""" - @FeatureNew('rust module', '0.57.0') + INFO = ModuleInfo('rust', '0.57.0') + def __init__(self, interpreter: 'Interpreter') -> None: super().__init__(interpreter) self._bindgen_bin: T.Optional['ExternalProgram'] = None diff --git a/mesonbuild/modules/unstable_simd.py b/mesonbuild/modules/unstable_simd.py index 8715a14..6766380 100644 --- a/mesonbuild/modules/unstable_simd.py +++ b/mesonbuild/modules/unstable_simd.py @@ -15,13 +15,12 @@ from .. import mesonlib, compilers, mlog from .. import build -from . import ExtensionModule - -from ..interpreterbase import FeatureNew +from . import ExtensionModule, ModuleInfo class SimdModule(ExtensionModule): - @FeatureNew('SIMD module', '0.42.0') + INFO = ModuleInfo('SIMD', '0.42.0') + def __init__(self, interpreter): super().__init__(interpreter) # FIXME add Altivec and AVX512. diff --git a/mesonbuild/modules/unstable_wayland.py b/mesonbuild/modules/unstable_wayland.py index 94c11f1..392e1a7 100644 --- a/mesonbuild/modules/unstable_wayland.py +++ b/mesonbuild/modules/unstable_wayland.py @@ -16,10 +16,10 @@ from __future__ import annotations import os import typing as T -from . import ExtensionModule, ModuleReturnValue +from . import ExtensionModule, ModuleReturnValue, ModuleInfo from ..build import CustomTarget from ..interpreter.type_checking import NoneType, in_set_validator -from ..interpreterbase import FeatureNew, typed_pos_args, typed_kwargs, KwargInfo +from ..interpreterbase import typed_pos_args, typed_kwargs, KwargInfo from ..mesonlib import File, MesonException if T.TYPE_CHECKING: @@ -45,7 +45,8 @@ if T.TYPE_CHECKING: class WaylandModule(ExtensionModule): - @FeatureNew('wayland module', '0.62.0') + INFO = ModuleInfo('wayland', '0.62.0') + def __init__(self, interpreter: Interpreter) -> None: super().__init__(interpreter) diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 58a08a7..17ee5f1 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -18,7 +18,7 @@ import re import typing as T -from . import ExtensionModule +from . import ExtensionModule, ModuleInfo from . import ModuleReturnValue from .. import mesonlib, build from .. import mlog @@ -55,6 +55,9 @@ class ResourceCompilerType(enum.Enum): wrc = 3 class WindowsModule(ExtensionModule): + + INFO = ModuleInfo('windows') + def __init__(self, interpreter: 'Interpreter'): super().__init__(interpreter) self._rescomp: T.Optional[T.Tuple[ExternalProgram, ResourceCompilerType]] = None |