diff --git a/docs/markdown/Qt6-module.md b/docs/markdown/Qt6-module.md index 8e8ec71e0..0a453dd41 100644 --- a/docs/markdown/Qt6-module.md +++ b/docs/markdown/Qt6-module.md @@ -39,6 +39,11 @@ It takes no positional arguments, and the following keyword arguments: *New in 0.60.0*: support for custom_target, custom_target_index, and generator_output. - `extra_args` string[]: Extra arguments to pass directly to `qt-uic` - `method` string: The method to use to detect Qt, see [[dependency]] + - `preserve_paths` bool: *New in 1.4.0*. If `true`, specifies that the output + files need to maintain their directory structure inside the target temporary + directory. For instance, when a file called `subdir/one.input` is processed + it generates a file `{target private directory}/subdir/one.out` when `true`, + and `{target private directory}/one.out` when `false` (default). ## compile_moc @@ -59,6 +64,11 @@ It takes no positional arguments, and the following keyword arguments: - `dependencies`: dependency objects whose include directories are used by moc. - `include_directories` (string | IncludeDirectory)[]: A list of `include_directory()` objects used when transpiling the .moc files + - `preserve_paths` bool: *New in 1.4.0*. If `true`, specifies that the output + files need to maintain their directory structure inside the target temporary + directory. For instance, when a file called `subdir/one.input` is processed + it generates a file `{target private directory}/subdir/one.out` when `true`, + and `{target private directory}/one.out` when `false` (default). ## preprocess @@ -96,7 +106,12 @@ This method takes the following keyword arguments: - `dependencies` Dependency[]: dependency objects needed by moc. - *Deprecated in 0.59.0.*: `sources`: a list of extra sources, which are added to the output unchanged. - + - `preserve_paths` bool: *Since 1.4.0*. If `true`, specifies that the output + files need to maintain their directory structure inside the target temporary + directory. For instance, when a file called `subdir/one.input` is processed + it generates a file `{target private directory}/subdir/one.out` when `true`, + and `{target private directory}/one.out` when `false` (default). + It returns an array of targets and sources to pass to a compilation target. ## compile_translations diff --git a/docs/markdown/_include_qt_base.md b/docs/markdown/_include_qt_base.md index adc6f7c6f..00d1f8344 100644 --- a/docs/markdown/_include_qt_base.md +++ b/docs/markdown/_include_qt_base.md @@ -28,6 +28,11 @@ It takes no positional arguments, and the following keyword arguments: - `extra_args` string[]: Extra arguments to pass directly to `qt-uic` - `method` string: The method to use to detect Qt, see `dependency()` for more information. + - `preserve_paths` bool: *Since 1.4.0*. If `true`, specifies that the output + files need to maintain their directory structure inside the target temporary + directory. For instance, when a file called `subdir/one.input` is processed + it generates a file `{target private directory}/subdir/one.out` when `true`, + and `{target private directory}/one.out` when `false` (default). ## compile_moc @@ -49,6 +54,11 @@ It takes no positional arguments, and the following keyword arguments: - `dependencies`: dependency objects whose include directories are used by moc. - `include_directories` (string | IncludeDirectory)[]: A list of `include_directory()` objects used when transpiling the .moc files + - `preserve_paths` bool: *New in 1.4.0*. If `true`, specifies that the output + files need to maintain their directory structure inside the target temporary + directory. For instance, when a file called `subdir/one.input` is processed + it generates a file `{target private directory}/subdir/one.out` when `true`, + and `{target private directory}/one.out` when `false` (default). ## preprocess @@ -78,6 +88,11 @@ This method takes the following keyword arguments: - `rcc_extra_arguments` string[]: any additional arguments to `rcc`. Since v0.49.0. - `dependencies` Dependency[]: dependency objects needed by moc. Available since v0.48.0. - `sources`: a list of extra sources, which are added to the output unchanged. Deprecated in 0.59.0. + - `preserve_paths` bool: *New in 1.4.0*. If `true`, specifies that the output + files need to maintain their directory structure inside the target temporary + directory. For instance, when a file called `subdir/one.input` is processed + it generates a file `{target private directory}/subdir/one.out` when `true`, + and `{target private directory}/one.out` when `false` (default). It returns an array of targets and sources to pass to a compilation target. diff --git a/docs/markdown/snippets/qt_preserve_path_from.md b/docs/markdown/snippets/qt_preserve_path_from.md new file mode 100644 index 000000000..1a0923a72 --- /dev/null +++ b/docs/markdown/snippets/qt_preserve_path_from.md @@ -0,0 +1,10 @@ +## Added `preserve_paths` keyword argument to qt module functions. + +In `qt4`, `qt5`, and `qt6` modules, `compile_ui`, `compile_moc`, and +`preprocess` functions now have a `preserve_paths` keyword argument. + +If `'true`, it specifies that the output files need to maintain their directory +structure inside the target temporary directory. For instance, when a file +called `subdir/one.input` is processed it generates a file +`{target private directory}/subdir/one.out` when `true`, +and `{target private directory}/one.out` when `false` (default). diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py index c2a315c7f..7effa1f58 100644 --- a/mesonbuild/modules/qt.py +++ b/mesonbuild/modules/qt.py @@ -48,6 +48,7 @@ if T.TYPE_CHECKING: sources: T.Sequence[T.Union[FileOrString, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]] extra_args: T.List[str] method: str + preserve_paths: bool class MocCompilerKwArgs(TypedDict): @@ -59,6 +60,7 @@ if T.TYPE_CHECKING: method: str include_directories: T.List[T.Union[str, build.IncludeDirs]] dependencies: T.List[T.Union[Dependency, ExternalLibrary]] + preserve_paths: bool class PreprocessKwArgs(TypedDict): @@ -73,6 +75,7 @@ if T.TYPE_CHECKING: include_directories: T.List[T.Union[str, build.IncludeDirs]] dependencies: T.List[T.Union[Dependency, ExternalLibrary]] method: str + preserve_paths: bool class HasToolKwArgs(kwargs.ExtractRequired): @@ -376,9 +379,10 @@ class QtBaseModule(ExtensionModule): required=True, ), KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]), - KwargInfo('method', str, default='auto') + KwargInfo('method', str, default='auto'), + KwargInfo('preserve_paths', bool, default=False, since='1.4.0'), ) - def compile_ui(self, state: 'ModuleState', args: T.Tuple, kwargs: 'UICompilerKwArgs') -> ModuleReturnValue: + def compile_ui(self, state: ModuleState, args: T.Tuple, kwargs: UICompilerKwArgs) -> ModuleReturnValue: """Compile UI resources into cpp headers.""" if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in kwargs['sources']): FeatureNew.single_use('qt.compile_ui: custom_target or generator for "sources" keyword argument', @@ -386,7 +390,7 @@ class QtBaseModule(ExtensionModule): out = self._compile_ui_impl(state, kwargs) return ModuleReturnValue(out, [out]) - def _compile_ui_impl(self, state: 'ModuleState', kwargs: 'UICompilerKwArgs') -> build.GeneratedList: + def _compile_ui_impl(self, state: ModuleState, kwargs: UICompilerKwArgs) -> build.GeneratedList: # Avoid the FeatureNew when dispatching from preprocess self._detect_tools(state, kwargs['method']) if not self.tools['uic'].found(): @@ -394,13 +398,14 @@ class QtBaseModule(ExtensionModule): "please check your qt{2} installation") raise MesonException(err_msg.format('UIC', f'uic-qt{self.qt_version}', self.qt_version)) + preserve_path_from = os.path.join(state.source_root, state.subdir) if kwargs['preserve_paths'] else None # TODO: This generator isn't added to the generator list in the Interpreter gen = build.Generator( self.tools['uic'], kwargs['extra_args'] + ['-o', '@OUTPUT@', '@INPUT@'], ['ui_@BASENAME@.h'], name=f'Qt{self.qt_version} ui') - return gen.process_files(kwargs['sources'], state) + return gen.process_files(kwargs['sources'], state, preserve_path_from) @FeatureNew('qt.compile_moc', '0.59.0') @noPosargs @@ -422,8 +427,9 @@ class QtBaseModule(ExtensionModule): KwargInfo('method', str, default='auto'), KwargInfo('include_directories', ContainerTypeInfo(list, (build.IncludeDirs, str)), listify=True, default=[]), KwargInfo('dependencies', ContainerTypeInfo(list, (Dependency, ExternalLibrary)), listify=True, default=[]), + KwargInfo('preserve_paths', bool, default=False, since='1.4.0'), ) - def compile_moc(self, state: 'ModuleState', args: T.Tuple, kwargs: 'MocCompilerKwArgs') -> ModuleReturnValue: + def compile_moc(self, state: ModuleState, args: T.Tuple, kwargs: MocCompilerKwArgs) -> ModuleReturnValue: if any(isinstance(s, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for s in kwargs['headers']): FeatureNew.single_use('qt.compile_moc: custom_target or generator for "headers" keyword argument', '0.60.0', state.subproject, location=state.current_node) @@ -433,7 +439,7 @@ class QtBaseModule(ExtensionModule): out = self._compile_moc_impl(state, kwargs) return ModuleReturnValue(out, [out]) - def _compile_moc_impl(self, state: 'ModuleState', kwargs: 'MocCompilerKwArgs') -> T.List[build.GeneratedList]: + def _compile_moc_impl(self, state: ModuleState, kwargs: MocCompilerKwArgs) -> T.List[build.GeneratedList]: # Avoid the FeatureNew when dispatching from preprocess self._detect_tools(state, kwargs['method']) if not self.tools['moc'].found(): @@ -458,18 +464,19 @@ class QtBaseModule(ExtensionModule): DEPFILE_ARGS: T.List[str] = ['--output-dep-file'] if self._moc_supports_depfiles else [] arguments = kwargs['extra_args'] + DEPFILE_ARGS + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@'] + preserve_path_from = os.path.join(state.source_root, state.subdir) if kwargs['preserve_paths'] else None if kwargs['headers']: moc_gen = build.Generator( self.tools['moc'], arguments, ['moc_@BASENAME@.cpp'], depfile='moc_@BASENAME@.cpp.d', name=f'Qt{self.qt_version} moc header') - output.append(moc_gen.process_files(kwargs['headers'], state)) + output.append(moc_gen.process_files(kwargs['headers'], state, preserve_path_from)) if kwargs['sources']: moc_gen = build.Generator( self.tools['moc'], arguments, ['@BASENAME@.moc'], depfile='@BASENAME@.moc.d', name=f'Qt{self.qt_version} moc source') - output.append(moc_gen.process_files(kwargs['sources'], state)) + output.append(moc_gen.process_files(kwargs['sources'], state, preserve_path_from)) return output @@ -487,8 +494,9 @@ class QtBaseModule(ExtensionModule): KwargInfo('method', str, default='auto'), KwargInfo('include_directories', ContainerTypeInfo(list, (build.IncludeDirs, str)), listify=True, default=[]), KwargInfo('dependencies', ContainerTypeInfo(list, (Dependency, ExternalLibrary)), listify=True, default=[]), + KwargInfo('preserve_paths', bool, default=False, since='1.4.0'), ) - def preprocess(self, state: 'ModuleState', args: T.List[T.Union[str, File]], kwargs: 'PreprocessKwArgs') -> ModuleReturnValue: + def preprocess(self, state: ModuleState, args: T.List[T.Union[str, File]], kwargs: PreprocessKwArgs) -> ModuleReturnValue: _sources = args[1:] if _sources: FeatureDeprecated.single_use('qt.preprocess positional sources', '0.59', state.subproject, location=state.current_node) @@ -502,7 +510,7 @@ class QtBaseModule(ExtensionModule): if kwargs['qresources']: # custom output name set? -> one output file, multiple otherwise - rcc_kwargs: 'ResourceCompilerKwArgs' = {'name': '', 'sources': kwargs['qresources'], 'extra_args': kwargs['rcc_extra_arguments'], 'method': method} + rcc_kwargs: ResourceCompilerKwArgs = {'name': '', 'sources': kwargs['qresources'], 'extra_args': kwargs['rcc_extra_arguments'], 'method': method} if args: name = args[0] if not isinstance(name, str): @@ -511,17 +519,23 @@ class QtBaseModule(ExtensionModule): sources.extend(self._compile_resources_impl(state, rcc_kwargs)) if kwargs['ui_files']: - ui_kwargs: 'UICompilerKwArgs' = {'sources': kwargs['ui_files'], 'extra_args': kwargs['uic_extra_arguments'], 'method': method} + ui_kwargs: UICompilerKwArgs = { + 'sources': kwargs['ui_files'], + 'extra_args': kwargs['uic_extra_arguments'], + 'method': method, + 'preserve_paths': kwargs['preserve_paths'], + } sources.append(self._compile_ui_impl(state, ui_kwargs)) if kwargs['moc_headers'] or kwargs['moc_sources']: - moc_kwargs: 'MocCompilerKwArgs' = { + moc_kwargs: MocCompilerKwArgs = { 'extra_args': kwargs['moc_extra_arguments'], 'sources': kwargs['moc_sources'], 'headers': kwargs['moc_headers'], 'include_directories': kwargs['include_directories'], 'dependencies': kwargs['dependencies'], 'method': method, + 'preserve_paths': kwargs['preserve_paths'], } sources.extend(self._compile_moc_impl(state, moc_kwargs)) diff --git a/test cases/frameworks/4 qt/mainWindow.h b/test cases/frameworks/4 qt/mainWindow.h index 7f6d90601..3be51a00f 100644 --- a/test cases/frameworks/4 qt/mainWindow.h +++ b/test cases/frameworks/4 qt/mainWindow.h @@ -3,7 +3,7 @@ #include #include -#include "ui_mainWindow.h" +#include "ui/ui_mainWindow.h" class NotificationModel; diff --git a/test cases/frameworks/4 qt/meson.build b/test cases/frameworks/4 qt/meson.build index f8ba1751f..759e6cc17 100644 --- a/test cases/frameworks/4 qt/meson.build +++ b/test cases/frameworks/4 qt/meson.build @@ -61,11 +61,15 @@ foreach qt : ['qt4', 'qt5', 'qt6'] method : get_option('method') ) # XML files that need to be compiled with the uic tol. - prep += qtmodule.compile_ui(sources : 'mainWindow.ui', method: get_option('method')) + prep += qtmodule.compile_ui( + sources : 'ui/mainWindow.ui', + method: get_option('method'), + preserve_paths: true) qtmodule.preprocess( - ui_files : 'mainWindow.ui', - method: get_option('method')) + ui_files : 'ui/mainWindow.ui', + method: get_option('method'), + preserve_paths: true) # Resource file(s) for rcc compiler extra_cpp_args = [] diff --git a/test cases/frameworks/4 qt/mainWindow.ui b/test cases/frameworks/4 qt/ui/mainWindow.ui similarity index 100% rename from test cases/frameworks/4 qt/mainWindow.ui rename to test cases/frameworks/4 qt/ui/mainWindow.ui