aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/modules/windows.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/modules/windows.py')
-rw-r--r--mesonbuild/modules/windows.py131
1 files changed, 78 insertions, 53 deletions
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index 8f1af2c..4aa7e3a 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -15,40 +15,58 @@
import enum
import os
import re
+import typing as T
+
-from .. import mlog
-from .. import mesonlib, build
-from ..mesonlib import MachineChoice, MesonException, extract_as_list
-from . import ModuleReturnValue
from . import ExtensionModule
-from ..interpreterbase import permittedKwargs, FeatureNewKwargs, flatten
+from . import ModuleReturnValue
+from .. import mesonlib, build
+from .. import mlog
+from ..interpreter.type_checking import DEPEND_FILES_KW, DEPENDS_KW, INCLUDE_DIRECTORIES
+from ..interpreterbase.decorators import ContainerTypeInfo, FeatureNew, KwargInfo, typed_kwargs, typed_pos_args
+from ..mesonlib import MachineChoice, MesonException
from ..programs import ExternalProgram
+if T.TYPE_CHECKING:
+ from . import ModuleState
+ from ..compilers import Compiler
+ from ..interpreter import Interpreter
+
+ from typing_extensions import TypedDict
+
+ class CompileResources(TypedDict):
+
+ depend_files: T.List[mesonlib.FileOrString]
+ depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
+ include_directories: T.List[T.Union[str, build.IncludeDirs]]
+ args: T.List[str]
+
class ResourceCompilerType(enum.Enum):
windres = 1
rc = 2
wrc = 3
class WindowsModule(ExtensionModule):
- def __init__(self, interpreter):
+ def __init__(self, interpreter: 'Interpreter'):
super().__init__(interpreter)
+ self._rescomp: T.Optional[T.Tuple[ExternalProgram, ResourceCompilerType]] = None
self.methods.update({
'compile_resources': self.compile_resources,
})
- def detect_compiler(self, compilers):
+ def detect_compiler(self, compilers: T.Dict[str, 'Compiler']) -> 'Compiler':
for l in ('c', 'cpp'):
if l in compilers:
return compilers[l]
raise MesonException('Resource compilation requires a C or C++ compiler.')
- def _find_resource_compiler(self, state):
+ def _find_resource_compiler(self, state: 'ModuleState') -> T.Tuple[ExternalProgram, ResourceCompilerType]:
# FIXME: Does not handle `native: true` executables, see
# See https://github.com/mesonbuild/meson/issues/1531
# Take a parameter instead of the hardcoded definition below
for_machine = MachineChoice.HOST
- if hasattr(self, '_rescomp'):
+ if self._rescomp:
return self._rescomp
# Will try cross / native file and then env var
@@ -80,22 +98,26 @@ class WindowsModule(ExtensionModule):
return self._rescomp
- @FeatureNewKwargs('windows.compile_resources', '0.47.0', ['depend_files', 'depends'])
- @permittedKwargs({'args', 'include_directories', 'depend_files', 'depends'})
- def compile_resources(self, state, args, kwargs):
- extra_args = mesonlib.stringlistify(flatten(kwargs.get('args', [])))
- wrc_depend_files = extract_as_list(kwargs, 'depend_files', pop = True)
- wrc_depends = extract_as_list(kwargs, 'depends', pop = True)
+ @typed_pos_args('windows.compile_resources', varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex), min_varargs=1)
+ @typed_kwargs(
+ 'winddows.compile_resoures',
+ DEPEND_FILES_KW.evolve(since='0.47.0'),
+ DEPENDS_KW.evolve(since='0.47.0'),
+ INCLUDE_DIRECTORIES.evolve(name='include_directories'),
+ KwargInfo('args', ContainerTypeInfo(list, str), default=[], listify=True),
+ )
+ def compile_resources(self, state: 'ModuleState',
+ args: T.Tuple[T.List[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex]]],
+ kwargs: 'CompileResources') -> ModuleReturnValue:
+ extra_args = kwargs['args'].copy()
+ wrc_depend_files = kwargs['depend_files']
+ wrc_depends = kwargs['depends']
for d in wrc_depends:
if isinstance(d, build.CustomTarget):
extra_args += state.get_include_args([
build.IncludeDirs('', [], False, [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(d))])
])
- inc_dirs = extract_as_list(kwargs, 'include_directories', pop = True)
- for incd in inc_dirs:
- if not isinstance(incd, (str, build.IncludeDirs)):
- raise MesonException('Resource include dirs should be include_directories().')
- extra_args += state.get_include_args(inc_dirs)
+ extra_args += state.get_include_args(kwargs['include_directories'])
rescomp, rescomp_type = self._find_resource_compiler(state)
if rescomp_type == ResourceCompilerType.rc:
@@ -119,53 +141,56 @@ class WindowsModule(ExtensionModule):
suffix = 'o'
res_args = extra_args + ['@INPUT@', '-o', '@OUTPUT@']
- res_targets = []
-
- def add_target(src):
- if isinstance(src, list):
- for subsrc in src:
- add_target(subsrc)
- return
-
- if isinstance(src, str):
- name_formatted = src
- name = os.path.join(state.subdir, src)
- elif isinstance(src, mesonlib.File):
- name_formatted = src.fname
- name = src.relative_name()
- elif isinstance(src, build.CustomTarget):
- if len(src.get_outputs()) > 1:
- raise MesonException('windows.compile_resources does not accept custom targets with more than 1 output.')
-
- # Chances are that src.get_filename() is already the name of that
- # target, add a prefix to avoid name clash.
- name_formatted = 'windows_compile_resources_' + src.get_filename()
- name = src.get_id()
- else:
- raise MesonException(f'Unexpected source type {src!r}. windows.compile_resources accepts only strings, files, custom targets, and lists thereof.')
-
+ res_targets: T.List[build.CustomTarget] = []
+
+ def get_names() -> T.Iterable[T.Tuple[str, str, T.Union[str, mesonlib.File, build.CustomTargetIndex]]]:
+ for src in args[0]:
+ if isinstance(src, str):
+ yield os.path.join(state.subdir, src), src, src
+ elif isinstance(src, mesonlib.File):
+ yield src.relative_name(), src.fname, src
+ elif isinstance(src, build.CustomTargetIndex):
+ FeatureNew.single_use('windows.compile_resource CustomTargetIndex in positional arguments', '0.61.0', state.subproject)
+ # This dance avoids a case where two indexs of the same
+ # target are given as separate arguments.
+ yield (f'{src.get_id()}_{src.target.get_outputs().index(src.output)}',
+ f'windows_compile_resources_{src.get_filename()}', src)
+ else:
+ if len(src.get_outputs()) > 1:
+ FeatureNew.single_use('windows.compile_resource CustomTarget with multiple outputs in positional arguments', '0.61.0', state.subproject)
+ for i, out in enumerate(src.get_outputs()):
+ # Chances are that src.get_filename() is already the name of that
+ # target, add a prefix to avoid name clash.
+ yield f'{src.get_id()}_{i}', f'windows_compile_resources_{i}_{out}', src[i]
+
+ for name, name_formatted, src in get_names():
# Path separators are not allowed in target names
name = name.replace('/', '_').replace('\\', '_').replace(':', '_')
name_formatted = name_formatted.replace('/', '_').replace('\\', '_').replace(':', '_')
+ output = f'{name}_@BASENAME@.{suffix}'
+ command: T.List[T.Union[str, ExternalProgram]] = []
+ command.append(rescomp)
+ command.extend(res_args)
res_kwargs = {
- 'output': name + '_@BASENAME@.' + suffix,
+ 'output': output,
'input': [src],
- 'command': [rescomp] + res_args,
'depend_files': wrc_depend_files,
'depends': wrc_depends,
}
# instruct binutils windres to generate a preprocessor depfile
if rescomp_type == ResourceCompilerType.windres:
- res_kwargs['depfile'] = res_kwargs['output'] + '.d'
- res_kwargs['command'] += ['--preprocessor-arg=-MD', '--preprocessor-arg=-MQ@OUTPUT@', '--preprocessor-arg=-MF@DEPFILE@']
+ res_kwargs['depfile'] = f'{output}.d'
+ command.extend(['--preprocessor-arg=-MD',
+ '--preprocessor-arg=-MQ@OUTPUT@',
+ '--preprocessor-arg=-MF@DEPFILE@'])
- res_targets.append(build.CustomTarget(name_formatted, state.subdir, state.subproject, res_kwargs))
+ res_kwargs['command'] = command
- add_target(args)
+ res_targets.append(build.CustomTarget(name_formatted, state.subdir, state.subproject, res_kwargs))
return ModuleReturnValue(res_targets, [res_targets])
-def initialize(*args, **kwargs):
- return WindowsModule(*args, **kwargs)
+def initialize(interp: 'Interpreter') -> WindowsModule:
+ return WindowsModule(interp)