Skip to content

Commit 632115e

Browse files
bruchar1dcbaker
authored andcommitted
Detect dependency changes in Windows rc compiler
The `rc.exe` resource compiler neither provides *depfile* support nor allows showing includes, as is possible with C or C++ compilers. Therefore, changes to files included by the `.rc` file did not trigger recompilation of the resource file. A workaround was added to *meson* by calling the preprocessor on the `.rc` file to detect the included headers and adding the result as a dependency to the resource compilation.
1 parent e216454 commit 632115e

File tree

3 files changed

+56
-7
lines changed

3 files changed

+56
-7
lines changed

docs/markdown/Windows-module.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ Compiles Windows `rc` files specified in the positional arguments.
2020
Returns a list of `CustomTarget` objects that you put in the list of sources for
2121
the target you want to have the resources in.
2222

23-
*Since 0.61.0* CustomTargetIndexes and CustomTargets with more than out output
24-
*may be used as positional arguments.
23+
*Since 0.61.0* `CustomTargetIndexes` and `CustomTargets` with more than one output
24+
may be used as positional arguments.
25+
26+
*Since 1.10.0* Changes to included header files are now detected when using
27+
`rc.exe` resource compiler.
2528

2629
This method has the following keyword arguments:
2730

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## windows.compile_resources now detects header changes with rc.exe
2+
3+
The `rc.exe` resource compiler neither provides *depfile* support nor
4+
allows showing includes, as is possible with C or C++ compilers.
5+
Therefore, changes to files included by the `.rc` file did not trigger
6+
recompilation of the resource file.
7+
8+
A workaround was added to *meson* by calling the preprocessor on the
9+
`.rc` file to detect the included headers and adding the result as a
10+
dependency to the resource compilation.

mesonbuild/modules/windows.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222
from . import ModuleState
2323
from ..compilers import Compiler
2424
from ..interpreter import Interpreter
25+
from ..interpreter.interpreter import SourceOutputs
2526

2627
from typing_extensions import TypedDict
2728

2829
class CompileResources(TypedDict):
29-
3030
depend_files: T.List[mesonlib.FileOrString]
31-
depends: T.List[T.Union[build.BuildTarget, build.CustomTarget]]
31+
depends: T.List[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]]
3232
include_directories: T.List[T.Union[str, build.IncludeDirs]]
3333
args: T.List[str]
3434

@@ -102,6 +102,33 @@ def _find_resource_compiler(self, state: 'ModuleState') -> T.Tuple[ExternalProgr
102102

103103
return self._rescomp
104104

105+
def get_preprocessor_target(self,
106+
name_formatted: str,
107+
src: T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex],
108+
include_directories: T.List[build.IncludeDirs],
109+
state: ModuleState) -> build.CustomTargetIndex:
110+
compiler = self.detect_compiler(state.environment.coredata.compilers[MachineChoice.HOST])
111+
_sources: T.List[T.Union[mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]] = self.interpreter.source_strings_to_files([src])
112+
sources = T.cast('T.List[SourceOutputs]', _sources)
113+
114+
tg = build.CompileTarget(
115+
name_formatted,
116+
state.subdir,
117+
state.subproject,
118+
state.environment,
119+
sources,
120+
'@PLAINNAME@.i',
121+
compiler.get_preprocessor(),
122+
state.backend,
123+
['-DRC_INVOKED'],
124+
include_directories,
125+
[],
126+
[])
127+
self.interpreter.add_target(tg.name, tg)
128+
129+
private_dir = os.path.relpath(state.backend.get_target_private_dir(tg), state.subdir)
130+
return build.CustomTargetIndex(tg, os.path.join(private_dir, tg.outputs[0]))
131+
105132
@typed_pos_args('windows.compile_resources', varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex), min_varargs=1)
106133
@typed_kwargs(
107134
'windows.compile_resources',
@@ -121,7 +148,8 @@ def compile_resources(self, state: 'ModuleState',
121148
extra_args += state.get_include_args([
122149
build.IncludeDirs('', [], False, [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(d))])
123150
])
124-
extra_args += state.get_include_args(kwargs['include_directories'])
151+
include_directories = self.interpreter.extract_incdirs(kwargs)
152+
extra_args += state.get_include_args(include_directories)
125153

126154
rescomp, rescomp_type = self._find_resource_compiler(state)
127155
if rescomp_type == ResourceCompilerType.rc:
@@ -178,12 +206,20 @@ def get_names() -> T.Iterable[T.Tuple[str, str, T.Union[str, mesonlib.File, buil
178206
command.append(rescomp)
179207
command.extend(res_args)
180208
depfile: T.Optional[str] = None
181-
# instruct binutils windres to generate a preprocessor depfile
209+
extra_depends = wrc_depends.copy()
182210
if rescomp_type == ResourceCompilerType.windres:
211+
# instruct binutils windres to generate a preprocessor depfile
183212
depfile = f'{output}.d'
184213
command.extend(['--preprocessor-arg=-MD',
185214
'--preprocessor-arg=-MQ@OUTPUT@',
186215
'--preprocessor-arg=-MF@DEPFILE@'])
216+
elif rescomp_type == ResourceCompilerType.rc:
217+
# use preprocessor to detect header dependencies
218+
extra_depends.append(self.get_preprocessor_target(
219+
name_formatted + '_i',
220+
src,
221+
include_directories,
222+
state))
187223

188224
res_targets.append(build.CustomTarget(
189225
name_formatted,
@@ -195,7 +231,7 @@ def get_names() -> T.Iterable[T.Tuple[str, str, T.Union[str, mesonlib.File, buil
195231
[output],
196232
depfile=depfile,
197233
depend_files=wrc_depend_files,
198-
extra_depends=wrc_depends,
234+
extra_depends=extra_depends,
199235
description='Compiling Windows resource {}',
200236
))
201237

0 commit comments

Comments
 (0)