From e3c8257fc96b45be725cc1a729397a3a9f7f2605 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 Oct 2021 13:55:41 -0700 Subject: modules/windows: add some easy type annotations This isn't complete, it's just the easy stuff --- mesonbuild/modules/windows.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 8f1af2c..931d908 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -15,40 +15,47 @@ 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 . import ModuleReturnValue +from .. import mesonlib, build +from .. import mlog from ..interpreterbase import permittedKwargs, FeatureNewKwargs, flatten +from ..mesonlib import MachineChoice, MesonException, extract_as_list from ..programs import ExternalProgram +if T.TYPE_CHECKING: + from . import ModuleState + from ..compilers import Compiler + from ..interpreter import Interpreter + 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 @@ -82,7 +89,7 @@ class WindowsModule(ExtensionModule): @FeatureNewKwargs('windows.compile_resources', '0.47.0', ['depend_files', 'depends']) @permittedKwargs({'args', 'include_directories', 'depend_files', 'depends'}) - def compile_resources(self, state, args, kwargs): + def compile_resources(self, state: 'ModuleState', 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) @@ -167,5 +174,5 @@ class WindowsModule(ExtensionModule): return ModuleReturnValue(res_targets, [res_targets]) -def initialize(*args, **kwargs): - return WindowsModule(*args, **kwargs) +def initialize(interp: 'Interpreter') -> WindowsModule: + return WindowsModule(interp) -- cgit v1.1 From dc1866aedcd4b66f5e0e476ddecb8e44a0618c8b Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 Oct 2021 14:02:22 -0700 Subject: modules/windows: use typed_pos_args --- mesonbuild/modules/windows.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 931d908..c1d5728 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -17,11 +17,13 @@ import os import re import typing as T + from . import ExtensionModule from . import ModuleReturnValue from .. import mesonlib, build from .. import mlog from ..interpreterbase import permittedKwargs, FeatureNewKwargs, flatten +from ..interpreterbase.decorators import typed_pos_args from ..mesonlib import MachineChoice, MesonException, extract_as_list from ..programs import ExternalProgram @@ -89,7 +91,10 @@ class WindowsModule(ExtensionModule): @FeatureNewKwargs('windows.compile_resources', '0.47.0', ['depend_files', 'depends']) @permittedKwargs({'args', 'include_directories', 'depend_files', 'depends'}) - def compile_resources(self, state: 'ModuleState', args, kwargs): + @typed_pos_args('windows.compile_resources', varargs=(str, mesonlib.File, build.CustomTarget), min_varargs=1) + def compile_resources(self, state: 'ModuleState', + args: T.Tuple[T.List[T.Union[str, mesonlib.File, build.CustomTarget]]], + kwargs) -> ModuleReturnValue: 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) @@ -128,12 +133,7 @@ class WindowsModule(ExtensionModule): res_targets = [] - def add_target(src): - if isinstance(src, list): - for subsrc in src: - add_target(subsrc) - return - + for src in args: if isinstance(src, str): name_formatted = src name = os.path.join(state.subdir, src) @@ -148,8 +148,6 @@ class WindowsModule(ExtensionModule): # 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.') # Path separators are not allowed in target names name = name.replace('/', '_').replace('\\', '_').replace(':', '_') @@ -170,8 +168,6 @@ class WindowsModule(ExtensionModule): res_targets.append(build.CustomTarget(name_formatted, state.subdir, state.subproject, res_kwargs)) - add_target(args) - return ModuleReturnValue(res_targets, [res_targets]) def initialize(interp: 'Interpreter') -> WindowsModule: -- cgit v1.1 From cc231de08ecff2a92230ad29faaa486bc809f92b Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 Oct 2021 14:31:25 -0700 Subject: modules/windows: use typed_kwargs --- mesonbuild/interpreter/type_checking.py | 9 ++++- mesonbuild/modules/windows.py | 59 +++++++++++++++++++++------------ run_mypy.py | 1 + 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 310f281..6925ef0 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -6,7 +6,7 @@ import typing as T from .. import compilers -from ..build import EnvironmentVariables, CustomTarget, BuildTarget, CustomTargetIndex, ExtractedObjects, GeneratedList +from ..build import EnvironmentVariables, CustomTarget, BuildTarget, CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs from ..coredata import UserFeatureOption from ..interpreterbase import TYPE_var from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo @@ -278,3 +278,10 @@ CT_INSTALL_DIR_KW: KwargInfo[T.List[T.Union[str, bool]]] = KwargInfo( ) CT_BUILD_BY_DEFAULT: KwargInfo[T.Optional[bool]] = KwargInfo('build_by_default', (bool, type(None)), since='0.40.0') + +INCLUDE_DIRECTORIES: KwargInfo[T.List[T.Union[str, IncludeDirs]]] = KwargInfo( + 'include_dirs', + ContainerTypeInfo(list, (str, IncludeDirs)), + listify=True, + default=[], +) diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index c1d5728..b6bdd9f 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -22,9 +22,9 @@ from . import ExtensionModule from . import ModuleReturnValue from .. import mesonlib, build from .. import mlog -from ..interpreterbase import permittedKwargs, FeatureNewKwargs, flatten -from ..interpreterbase.decorators import typed_pos_args -from ..mesonlib import MachineChoice, MesonException, extract_as_list +from ..interpreter.type_checking import DEPEND_FILES_KW, DEPENDS_KW, INCLUDE_DIRECTORIES +from ..interpreterbase.decorators import ContainerTypeInfo, KwargInfo, typed_kwargs, typed_pos_args +from ..mesonlib import MachineChoice, MesonException from ..programs import ExternalProgram if T.TYPE_CHECKING: @@ -32,6 +32,15 @@ if T.TYPE_CHECKING: 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 @@ -89,25 +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'}) @typed_pos_args('windows.compile_resources', varargs=(str, mesonlib.File, build.CustomTarget), 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]]], - kwargs) -> ModuleReturnValue: - 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) + 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: @@ -131,16 +141,16 @@ class WindowsModule(ExtensionModule): suffix = 'o' res_args = extra_args + ['@INPUT@', '-o', '@OUTPUT@'] - res_targets = [] + res_targets: T.List[build.CustomTarget] = [] - for src in args: + for src in args[0]: 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): + else: if len(src.get_outputs()) > 1: raise MesonException('windows.compile_resources does not accept custom targets with more than 1 output.') @@ -152,19 +162,26 @@ class WindowsModule(ExtensionModule): # 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_kwargs['command'] = command res_targets.append(build.CustomTarget(name_formatted, state.subdir, state.subproject, res_kwargs)) diff --git a/run_mypy.py b/run_mypy.py index d6903f5..38ac676 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -44,6 +44,7 @@ modules = [ 'mesonbuild/modules/qt.py', 'mesonbuild/modules/unstable_external_project.py', 'mesonbuild/modules/unstable_rust.py', + 'mesonbuild/modules/windows.py', 'mesonbuild/mparser.py', 'mesonbuild/msetup.py', 'mesonbuild/mtest.py', -- cgit v1.1 From 88060d47c11885f4b820c95fecd5dde30936fac7 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 Oct 2021 14:36:34 -0700 Subject: modules/windows: allow CustomTargetIndex for compile_resources In the positional arguments --- mesonbuild/modules/windows.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index b6bdd9f..568ad97 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -23,7 +23,7 @@ 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, KwargInfo, typed_kwargs, typed_pos_args +from ..interpreterbase.decorators import ContainerTypeInfo, FeatureNew, KwargInfo, typed_kwargs, typed_pos_args from ..mesonlib import MachineChoice, MesonException from ..programs import ExternalProgram @@ -98,7 +98,7 @@ class WindowsModule(ExtensionModule): return self._rescomp - @typed_pos_args('windows.compile_resources', varargs=(str, mesonlib.File, build.CustomTarget), min_varargs=1) + @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'), @@ -107,7 +107,7 @@ class WindowsModule(ExtensionModule): 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]]], + 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'] @@ -151,6 +151,8 @@ class WindowsModule(ExtensionModule): name_formatted = src.fname name = src.relative_name() else: + if isinstance(src, build.CustomTargetIndex): + FeatureNew.single_use('windows.compile_resource CustomTargetIndex in positional arguments', '0.61.0', state.subproject) if len(src.get_outputs()) > 1: raise MesonException('windows.compile_resources does not accept custom targets with more than 1 output.') -- cgit v1.1 From 0d52a6161a7572b6132643d16f8a16ab7ba6cf66 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 Oct 2021 14:47:57 -0700 Subject: build: Add missing type annotation --- mesonbuild/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 311732e..1a365df 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -2684,7 +2684,7 @@ class CustomTargetIndex(HoldableObject): def get_filename(self) -> str: return self.output - def get_id(self): + def get_id(self) -> str: return self.target.get_id() def get_all_link_deps(self): -- cgit v1.1 From 6849baa47633d2986c049cd68916bc9ce95ba2d0 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 Oct 2021 14:48:07 -0700 Subject: modules/windows: allow CustomTargets with more than one output for compile_resources --- docs/markdown/Windows-module.md | 18 ++++++++++-- docs/markdown/snippets/windows_custom_targets.md | 22 ++++++++++++++ mesonbuild/modules/windows.py | 37 +++++++++++++----------- 3 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 docs/markdown/snippets/windows_custom_targets.md diff --git a/docs/markdown/Windows-module.md b/docs/markdown/Windows-module.md index a7131a7..06b3eb2 100644 --- a/docs/markdown/Windows-module.md +++ b/docs/markdown/Windows-module.md @@ -7,10 +7,22 @@ Windows. ### compile_resources +``` + windows.compile_resources(...(string | File | CustomTarget | CustomTargetIndex), + args: []string, + depend_files: [](string | File), + depends: [](BuildTarget | CustomTarget) + include_directories: [](IncludeDirectories | string)): []CustomTarget +``` + Compiles Windows `rc` files specified in the positional arguments. -Returns an opaque object that you put in the list of sources for the -target you want to have the resources in. This method has the -following keyword argument. +Returns a list of `CustomTarget` objects that you put in the list of sources for +the target you want to have the resources in. + +*Since 0.61.0* CustomTargetIndexs and CustomTargets with more than out output +*may be used as positional arguments. + +This method has the following keyword arguments: - `args` lists extra arguments to pass to the resource compiler - `depend_files` lists resource files that the resource script depends on diff --git a/docs/markdown/snippets/windows_custom_targets.md b/docs/markdown/snippets/windows_custom_targets.md new file mode 100644 index 0000000..cbc2f9d --- /dev/null +++ b/docs/markdown/snippets/windows_custom_targets.md @@ -0,0 +1,22 @@ +## Windows.compile_resources CustomTarget + +Previously the Windows module only accepted CustomTargets with one output, it +now accepts them with more than one output, and creates a windows resource +target for each output. Additionally it now accepts indexes of CustomTargets + +```meson + +ct = custom_target( + 'multiple', + output : ['resource', 'another resource'], + ... +) + +ct2 = custom_target( + 'slice', + output : ['resource', 'not a resource'], + ... +) + +resources = windows.compile_resources(ct, ct2[0]) +``` diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 568ad97..4aa7e3a 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -143,24 +143,27 @@ class WindowsModule(ExtensionModule): res_targets: T.List[build.CustomTarget] = [] - for src in args[0]: - 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() - else: - if isinstance(src, build.CustomTargetIndex): + 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) - 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() - + # 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(':', '_') -- cgit v1.1