Repository: mesonbuild/meson

Issue:
Vala: targets for individual sources should depend on gresource dependencies
**Describe the bug**
Targets for individual vala files do not depend on sources for gresources compiled alongside them. This becomes a problem in a case where a generated `.ui` file is referenced from vala, since those are used by valac.

I'm currently working around this by using

```meson
fs = import('fs')
program_sources = []
foreach file: program_sources_native
  program_sources += custom_target(
    input: file,
    output:  'copied_'+fs.name(file),
    command: [find_program('cat')],
    feed: true,
    capture: true,
    depends: ui_resource_generator_tgt
  )
endforeach
```

...which is less than ideal, to put it mildly (and breaks syntax highlighting in gnome builder), but seems to be the only way to introduce a dependency on a target for *sources*.

**To Reproduce**
Here's an example project demonstrating the issue: [Archive.zip](https://github.com/mesonbuild/meson/files/13117121/Archive.zip). Explicitly building only target `test_prog.p/test.c` will lead to the error in question, building all will be luck-based.

It's also worth noting that I have to manually pass `--gresourcedir` to vala here, which is also an issue in its own right (although it's MUCH easier to work around than the main issue).

**Expected behavior**
Vala files should depend on resources built alongside them. While this may slightly increase build times for unaffected projects it has to be done in order to allow using generated .ui files.

**system parameters**
* Is this a [cross build](https://mesonbuild.com/Cross-compilation.html) or just a plain native build (for the same computer)? Native
* what operating system Manjaro
* what Python version are you using 3.11.5
* what `meson --version` 1.2.2
* what `ninja --version` if it's a Ninja build 1.11.1



Discussion:

Resolving patch:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1709,11 +1709,21 @@ def generate_vala_compile(self, target: build.BuildTarget) -> \
                 # Install GIR to default location if requested by user
                 if len(target.install_dir) > 3 and target.install_dir[3] is True:
                     target.install_dir[3] = os.path.join(self.environment.get_datadir(), 'gir-1.0')
-        # Detect gresources and add --gresources arguments for each
+        # Detect gresources and add --gresources/--gresourcesdir arguments for each
+        gres_dirs = []
         for gensrc in other_src[1].values():
             if isinstance(gensrc, modules.GResourceTarget):
                 gres_xml, = self.get_custom_target_sources(gensrc)
                 args += ['--gresources=' + gres_xml]
+                for source_dir in gensrc.source_dirs:
+                    gres_dirs += [os.path.join(self.get_target_dir(gensrc), source_dir)]
+                # Ensure that resources are built before vala sources
+                # This is required since vala code using [GtkTemplate] effectively depends on .ui files
+                # GResourceHeaderTarget is not suitable due to lacking depfile
+                gres_c, = gensrc.get_outputs()
+                extra_dep_files += [os.path.join(self.get_target_dir(gensrc), gres_c)]
+        for gres_dir in OrderedSet(gres_dirs):
+            args += [f'--gresourcesdir={gres_dir}']
         dependency_vapis = self.determine_dep_vapis(target)
         extra_dep_files += dependency_vapis
         extra_dep_files.extend(self.get_target_depend_files(target))
diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py
--- a/mesonbuild/modules/__init__.py
+++ b/mesonbuild/modules/__init__.py
@@ -264,7 +264,7 @@ def __init__(self, return_value: T.Optional['TYPE_var'],
         self.new_objects: T.List[T.Union['TYPE_var', 'mesonlib.ExecutableSerialisation']] = new_objects
 
 class GResourceTarget(build.CustomTarget):
-    pass
+    source_dirs: T.List[str] = []
 
 class GResourceHeaderTarget(build.CustomTarget):
     pass
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -459,7 +459,10 @@ def compile_resources(self, state: 'ModuleState', args: T.Tuple[str, 'FileOrStri
         # Always include current directory, but after paths set by user
         source_dirs.append(os.path.join(state.build_to_src, state.subdir))
 
-        for source_dir in OrderedSet(source_dirs):
+        # Clean up duplicate directories
+        source_dirs = list(OrderedSet(os.path.normpath(dir) for dir in source_dirs))
+
+        for source_dir in source_dirs:
             cmd += ['--sourcedir', source_dir]
 
         if kwargs['c_name']:
@@ -518,6 +521,7 @@ def compile_resources(self, state: 'ModuleState', args: T.Tuple[str, 'FileOrStri
             install_dir=[kwargs['install_dir']] if kwargs['install_dir'] else [],
             install_tag=['runtime'],
         )
+        target_c.source_dirs = source_dirs
 
         if gresource: # Only one target for .gresource files
             return ModuleReturnValue(target_c, [target_c])


Test patch:
diff --git a/test cases/vala/28 generated ui file/TestBox.ui.in b/test cases/vala/28 generated ui file/TestBox.ui.in
new file mode 100644
--- /dev/null
+++ b/test cases/vala/28 generated ui file/TestBox.ui.in	
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk" version="3.0"/>
+  <template class="TestBox" parent="GtkBox">
+  </template>
+</interface>
diff --git a/test cases/vala/28 generated ui file/meson.build b/test cases/vala/28 generated ui file/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/vala/28 generated ui file/meson.build	
@@ -0,0 +1,34 @@
+project('demo', 'c', 'vala')
+
+gnome = import('gnome', required: false)
+
+if not gnome.found()
+  error('MESON_SKIP_TEST: gnome module not supported')
+endif
+
+deps = [
+  dependency('glib-2.0', version : '>=2.50'),
+  dependency('gobject-2.0'),
+  dependency('gtk+-3.0'),
+]
+
+ui_tgt = custom_target(
+  input: 'TestBox.ui.in',
+  output:  'TestBox.ui',
+  command: [find_program('cat')],
+  feed: true,
+  capture: true,
+)
+
+resources = gnome.compile_resources('test-resources',
+  'test.gresource.xml',
+  c_name: 'test_res',
+  dependencies: ui_tgt,
+)
+
+executable(
+  'demo',
+  'test.vala',
+  resources,
+  dependencies: deps,
+)
diff --git a/test cases/vala/28 generated ui file/test.gresource.xml b/test cases/vala/28 generated ui file/test.gresource.xml
new file mode 100644
--- /dev/null
+++ b/test cases/vala/28 generated ui file/test.gresource.xml	
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/com/mesonbuild/test">
+    <file>TestBox.ui</file>
+  </gresource>
+</gresources>
diff --git a/test cases/vala/28 generated ui file/test.vala b/test cases/vala/28 generated ui file/test.vala
new file mode 100644
--- /dev/null
+++ b/test cases/vala/28 generated ui file/test.vala	
@@ -0,0 +1,7 @@
+[GtkTemplate (ui = "/com/mesonbuild/test/TestBox.ui")]
+class TestBox: Gtk.Box {
+}
+
+int main() {
+    return 0;
+}