Repository: mesonbuild/meson

Issue:
compile_resources of Windows module regressed since 0.44
My build builds several executables in different subdirectories included in a main meson.build using 'subdir'.

Each of these sub meson.builds compiles a file named 'version.rc' using code like this:
```
  if host_machine.system() == 'windows'
    foo_sources += import('windows').compile_resources( 'src/version.rc' )
  endif
```

This works fine with meson versions up to 0.44.1. All later versions produce the error

> ERROR: Multiple producers for Ninja target "foo/version.res". Please rename your targets.

But renaming all 'version.rc' files to e.g. 'foo_version.rc' is not an option. And C++ files that carry identical names in different subdirectories aren't a problem either.


Discussion:
What's the latest version of Meson that you have tested with?
I tried 0.47.1 just before finally reporting the issue.
So the main difference from before, is that now you should only call `compile_resources()` on a file exactly once. Can you try doing that instead of defining it multiple times? Earlier it would generate the resource file multiple times in different subdirs which is inefficient and also less flexible.
Well, my source tree is like this:
```
    meson.build
    :
    +--exe1/
    :   :  meson.build
    :   :
    :   +--src/
    :       main.cpp
    :       version.rc
    +--exe2/
    :   :  meson.build
    :   :
    :   +--src/
    :        main.cpp
    :        version.rc
    +--exe3/
    :   :  meson.build
    :   :
    :   +--src_dll/
    :   :    main.cpp
    :   :    version.rc
    :   :
    :   +--src_exe/
    :        main.cpp
    :        version.rc
    :
```

And ASFAIK I'm calling ``compile_resources`` only once for each ``version.rc``. meson seems to pull each ``version.res`` to the top level of the build directory while it actually belongs to a subdir-build.

If I understand you correctly, it isn't possible anymore to have a structure like in ``exe3`` where two ``version.rc`` files exist in one subdir build?
This looks similar (but not the same as) to #3575, which was supposed to be fixed by #3715.

The error is different here because the problem seems to be:

> ERROR: Multiple producers for Ninja target "foo/version.res". Please rename your targets.

Which should be impossible if they are indeed being generated in different subdirs. Perhaps we are simply missing correct usage of `subdir` here.
I guess the first step is creating a sample project that reproduces this, so it can be investigated further.

Resolving patch:
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -88,35 +88,38 @@ def add_target(src):
             if hasattr(src, 'held_object'):
                 src = src.held_object
 
-            res_kwargs = {
-                'output': '@BASENAME@.' + suffix,
-                'input': [src],
-                'command': [rescomp] + res_args,
-                'depend_files': wrc_depend_files,
-                'depends': wrc_depends,
-            }
-
             if isinstance(src, str):
-                name = 'file {!r}'.format(os.path.join(state.subdir, src))
+                name_format = 'file {!r}'
+                name = format(os.path.join(state.subdir, src))
             elif isinstance(src, mesonlib.File):
-                name = 'file {!r}'.format(src.relative_name())
+                name_format = 'file {!r}'
+                name = format(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 = 'target {!r}'.format(src.get_id())
+                name_format = 'target {!r}'
+                name = format(src.get_id())
             else:
                 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('\\', '_')
 
+            res_kwargs = {
+                'output': name + '_@BASENAME@.' + suffix,
+                'input': [src],
+                'command': [rescomp] + res_args,
+                'depend_files': wrc_depend_files,
+                'depends': wrc_depends,
+            }
+
             # instruct binutils windres to generate a preprocessor depfile
             if comp.id != 'msvc':
                 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, state.subdir, state.subproject, res_kwargs))
+            res_targets.append(build.CustomTarget('Windows resource for ' + name_format.format(name), state.subdir, state.subproject, res_kwargs))
 
         add_target(args)
 


Test patch:
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build b/test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/meson.build	
@@ -0,0 +1,5 @@
+dll_res = win.compile_resources('src_dll/version.rc')
+shared_library('lib3', 'src_dll/main.c', dll_res)
+
+exe_res = win.compile_resources('src_exe/version.rc')
+executable('exe3', 'src_exe/main.c', exe_res)
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/main.c	
@@ -0,0 +1,6 @@
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+  return TRUE;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_dll/version.rc	
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION    1,0,0,0
+  PRODUCTVERSION 1,0,0,0
+  FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
+  FILEFLAGS      0
+  FILEOS         VOS__WINDOWS32
+  FILETYPE       VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/main.c	
@@ -0,0 +1,3 @@
+int main(int argc, char **argv) {
+    return 0;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe3/src_exe/version.rc	
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION    1,0,0,0
+  PRODUCTVERSION 1,0,0,0
+  FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
+  FILEFLAGS      0
+  FILEOS         VOS__WINDOWS32
+  FILETYPE       VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build b/test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/meson.build	
@@ -0,0 +1,5 @@
+dll_res = win.compile_resources(files('src_dll/version.rc'))
+shared_library('lib4', 'src_dll/main.c', dll_res)
+
+exe_res = win.compile_resources(files('src_exe/version.rc'))
+executable('exe4', 'src_exe/main.c', exe_res)
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/main.c	
@@ -0,0 +1,6 @@
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+  return TRUE;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_dll/version.rc	
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION    1,0,0,0
+  PRODUCTVERSION 1,0,0,0
+  FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
+  FILEFLAGS      0
+  FILEOS         VOS__WINDOWS32
+  FILETYPE       VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/main.c	
@@ -0,0 +1,3 @@
+int main(int argc, char **argv) {
+    return 0;
+}
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc
new file mode 100644
--- /dev/null
+++ b/test cases/windows/15 resource scripts with duplicate filenames/exe4/src_exe/version.rc	
@@ -0,0 +1,11 @@
+ #include <windows.h>
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION    1,0,0,0
+  PRODUCTVERSION 1,0,0,0
+  FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
+  FILEFLAGS      0
+  FILEOS         VOS__WINDOWS32
+  FILETYPE       VFT_APP
+BEGIN
+END
diff --git a/test cases/windows/15 resource scripts with duplicate filenames/meson.build b/test cases/windows/15 resource scripts with duplicate filenames/meson.build
--- a/test cases/windows/15 resource scripts with duplicate filenames/meson.build	
+++ b/test cases/windows/15 resource scripts with duplicate filenames/meson.build	
@@ -5,6 +5,8 @@ win = import('windows')
 subdir('a')
 subdir('b')
 subdir('c')
+subdir('exe3')
+subdir('exe4')
 
 main = win.compile_resources('rsrc.rc')