Browse Source

windows: reduce chance of going over path limit in backend/vs

When building with vs2019 (not ninja), a path length error will be thrown
if the path to a resource file is even remotely deep within the tree.

This is largely because the target name includes the string "Windows
resource for file 'full path'", which is then expanded twice (once for
the .vcxproj itself, and once for IntDir) and added to the full path.
When combined with the tiny path limits on Windows, it is easy to exceed
path limits.

This error is largely avoided by the ninja back-end. Unlike the
vs back-end, the ninja back-end does not use target.get_id() as part of
the project file path, nor does it use target.get_id() as part of

Example error:

error MSB4184: The expression "[MSBuild]::NormalizePath(
f3f7317@@Windows resource for file
f3f7317@@Windows resource for file
vcxproj.CopyComplete)" cannot be evaluated. Path:
@@Windows resource for file
@@Windows resource for file
vcxproj.CopyComplete exceeds the OS max path limit.
The fully qualified file name must be less than 260 characters.
Peter Harris Nirbheek Chauhan 1 month ago
1 changed files with 5 additions and 4 deletions
  1. +5

+ 5
- 4
mesonbuild/modules/ View File

@@ -119,22 +119,23 @@ class WindowsModule(ExtensionModule):
src = unholder(src)

if isinstance(src, str):
name_format = 'file {!r}'
name_formatted = src
name = os.path.join(state.subdir, src)
elif isinstance(src, mesonlib.File):
name_format = 'file {!r}'
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.')

name_format = 'target {!r}'
name_formatted = src.get_basename()
name = src.get_id()
raise MesonException('Unexpected source type {!r}. windows.compile_resources accepts only strings, files, custom targets, and lists thereof.'.format(src))

# Path separators are not allowed in target names
name = name.replace('/', '_').replace('\\', '_')
name_formatted = name_formatted.replace('/', '_').replace('\\', '_')

res_kwargs = {
'output': name + '_@BASENAME@.' + suffix,
@@ -149,7 +150,7 @@ class WindowsModule(ExtensionModule):
res_kwargs['depfile'] = res_kwargs['output'] + '.d'
res_kwargs['command'] += ['--preprocessor-arg=-MD', '--preprocessor-arg=-MQ@OUTPUT@', '--preprocessor-arg=-MF@DEPFILE@']

res_targets.append(build.CustomTarget('Windows resource for ' + name_format.format(name), state.subdir, state.subproject, res_kwargs))
res_targets.append(build.CustomTarget(name_formatted, state.subdir, state.subproject, res_kwargs))