Repository: mesonbuild/meson

Issue:
@BUILD_ROOT@ and @SOURCE_ROOT@ don't get replaced before running gtk-doc helper
This happens when building gstreamer with gtk-doc enabled.
Running `git bisect` shows it is caused by commit 976c9ab.

```
Running custom install script '/usr/local/bin/python3 /tmp/meson/meson.py --internal gtkdoc --sourcedir=/home/lantw44/gnome/source/gstreamer --builddir=/tmp/gstreamer-build --subdir=docs/gst --headerdirs=/home/lantw44/gnome/source/gstreamer/docs/gst/../../gst --mainfile=gstreamer-docs.sgml --modulename=gstreamer --mode=auto --scanargs=--deprecated-guards=GST_DISABLE_DEPRECATED@@--ignore-decorators=GST_EXPORT@@--ignore-headers=gettext.h glib-compat-private.h glib-compat.h gst-i18n-app.h gst-i18n-lib.h gst_private.h gstelementdetails.h gstmacros.h grammar.tab.h grammar.tab.pre.h math-compat.h types.h --gobjects-types-file=/tmp/gstreamer-build/docs/gst/gstreamer.types --content-files=building.xml@@running.xml@@/tmp/gstreamer-build/docs/version.entities --cflags=-I@BUILD_ROOT@/. -I@SOURCE_ROOT@/. -I/home/lantw44/gnome/devinstall/include/glib-2.0 -I/home/lantw44/gnome/devinstall/lib/glib-2.0/include -pthread --ldflags=-lgstreamer-1.0 -L/tmp/gstreamer-build/gst -Wl,-rpath /tmp/gstreamer-build/gst -L/home/lantw44/gnome/devinstall/lib -lgobject-2.0 -lglib-2.0 -lintl -lgmodule-2.0 -pthread -lm -L/usr/local/lib -lunwind -lexecinfo --cc=clang -pedantic -std=c11 --ld=clang -pedantic -std=c11'
Building documentation for gstreamer

Error in gtkdoc helper script:
'gtkdoc-scangobj' failed with status 1
gstreamer-scan.c:7:10: fatal error: 'gst/gst.h' file not found
#include <gst/gst.h>
         ^
1 error generated.
Traceback (most recent call last):
  File "/home/lantw44/gnome/devinstall/bin/gtkdoc-scangobj", line 69, in <module>
    sys.exit(scangobj.run(options))
  File "/home/lantw44/gnome/devinstall/share/gtk-doc/python/gtkdoc/scangobj.py", line 1255, in run
    res = subprocess.check_call(command, shell=True)
  File "/usr/local/lib/python2.7/subprocess.py", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'clang -pedantic -std=c11 >/dev/null -I@BUILD_ROOT@/. -I@SOURCE_ROOT@/. -I/home/lantw44/gnome/devinstall/include/glib-2.0 -I/home/lantw44/gnome/devinstall/lib/glib-2.0/include -pthread -c -o gstreamer-scan.o gstreamer-scan.c' returned non-zero exit status 1
```


Discussion:
Apparently this is not fixed even in `0.40.1`:

```
ninja -C _build/ gtk4-doc 
ninja: Entering directory `_build/'
[0/1] 'Running external command gtk4-doc.'
Building documentation for gtk4

Error in gtkdoc helper script:
'gtkdoc-scangobj' failed with status 1
gtk4-scan.c:7:10: fatal error: gtk/gtkunixprint.h: No such file or directory
 #include <gtk/gtkunixprint.h>
          ^~~~~~~~~~~~~~~~~~~~
compilation terminated.
Traceback (most recent call last):
  File "/home/ebassi/gnome/install/bin/gtkdoc-scangobj", line 69, in <module>
    sys.exit(scangobj.run(options))
  File "/home/ebassi/gnome/install/share/gtk-doc/python/gtkdoc/scangobj.py", line 1255, in run
    res = subprocess.check_call(command, shell=True)
  File "/usr/lib64/python2.7/subprocess.py", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'gcc >/dev/null -I@BUILD_ROOT@/. -I@SOURCE_ROOT@/. -I@BUILD_ROOT@/gtk -I@SOURCE_ROOT@/gtk -pthread -I/home/ebassi/gnome/install/include/glib-2.0 -I/home/ebassi/gnome/install/lib/glib-2.0/include -I/home/ebassi/gnome/install/include/gio-unix-2.0/ -I/home/ebassi/gnome/install/include/at-spi2-atk/2.0 -I/home/ebassi/gnome/install/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -I/home/ebassi/gnome/install/include/pango-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/harfbuzz -I/home/ebassi/gnome/install/include/gdk-pixbuf-2.0 -I/home/ebassi/gnome/install/include/atk-1.0 -I/home/ebassi/gnome/install/include/graphene-1.0 -I/home/ebassi/gnome/install/lib/graphene-1.0/include -I@BUILD_ROOT@/gdk/x11 -I@SOURCE_ROOT@/gdk/x11 -I@BUILD_ROOT@/gdk/. -I@SOURCE_ROOT@/gdk/. -c -o gtk4-scan.o gtk4-scan.c' returned non-zero exit status 1

FAILED: gtk4-doc 
'/usr/bin/python3' '/usr/bin/meson' '--internal' 'commandrunner' '/home/ebassi/Sources/gtk+-meson' '/home/ebassi/Sources/gtk+-meson/_build' 'docs/reference/gtk' '/usr/bin/mesonintrospect' '/usr/bin/python3' '/usr/bin/meson' '--internal' 'gtkdoc' '--sourcedir=/home/ebassi/Sources/gtk+-meson' '--builddir=/home/ebassi/Sources/gtk+-meson/_build' '--subdir=docs/reference/gtk' '--headerdirs=/home/ebassi/Sources/gtk+-meson/gtk@@/home/ebassi/Sources/gtk+-meson/_build/gtk' '--mainfile=gtk4-docs.xml' '--modulename=gtk4' '--mode=auto' '--scanargs=--ignore-decorators=_GDK_EXTERN|G_GNUC_WARN_UNUSED_RESULT@@--ignore-headers=' '--gobjects-types-file=gtk4.types' '--fixxrefargs=--html-dir=/home/ebassi/gnome/install/share/gtk-doc/html@@--extra-dir=/home/ebassi/gnome/install/share/gtk-doc/html/glib@@--extra-dir=/home/ebassi/gnome/install/share/gtk-doc/html/gobject@@--extra-dir=/home/ebassi/gnome/install/share/gtk-doc/html/gio@@--extra-dir=/usr/share/gtk-doc/html/cairo@@--extra-dir=/home/ebassi/gnome/install/share/gtk-doc/html/gdk-pixbuf@@--extra-dir=../gdk@@--extra-dir=../gsk' '--cflags=-I@BUILD_ROOT@/. -I@SOURCE_ROOT@/. -I@BUILD_ROOT@/gtk -I@SOURCE_ROOT@/gtk -pthread -I/home/ebassi/gnome/install/include/glib-2.0 -I/home/ebassi/gnome/install/lib/glib-2.0/include -I/home/ebassi/gnome/install/include/gio-unix-2.0/ -I/home/ebassi/gnome/install/include/at-spi2-atk/2.0 -I/home/ebassi/gnome/install/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -I/home/ebassi/gnome/install/include/pango-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libdrm -I/usr/include/harfbuzz -I/home/ebassi/gnome/install/include/gdk-pixbuf-2.0 -I/home/ebassi/gnome/install/include/atk-1.0 -I/home/ebassi/gnome/install/include/graphene-1.0 -I/home/ebassi/gnome/install/lib/graphene-1.0/include -I@BUILD_ROOT@/gdk/x11 -I@SOURCE_ROOT@/gdk/x11 -I@BUILD_ROOT@/gdk/. -I@SOURCE_ROOT@/gdk/.' '--ldflags=-lgtk-4 -L/home/ebassi/Sources/gtk+-meson/_build/gtk -Wl,-rpath /home/ebassi/Sources/gtk+-meson/_build/gtk -L/home/ebassi/gnome/install/lib -lgmodule-2.0 -pthread -lglib-2.0 -lgio-2.0 -lgobject-2.0 -latk-bridge-2.0 -lpangocairo-1.0 -lpango-1.0 -lcairo -lcairo-gobject -lfontconfig -lfreetype -lgdk_pixbuf-2.0 -latk-1.0 -lepoxy -lm -lgraphene-1.0 -lXi -lX11 -lpangoft2-1.0 -lvulkan -lrt -lxkbcommon -lwayland-client -lwayland-cursor -lwayland-egl -lXrender -lXext -lXcursor -lXdamage -lXfixes -lXcomposite -lXrandr -lXinerama' '--cc=ccache cc' '--ld=ccache cc'
ninja: build stopped: subcommand failed.
```

Found by @ebassi. Can we please add a test while fixing it this time? ;)
There is a test, we just can't run it until gtk-doc starts working with spaces in path.
Is it expected that I still get occurances of `@BUILD_ROOT@` in the `ninja.build` file with git master? These should all have been resolved before writing the `ninja.build` file, right?

Resolving patch:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -510,12 +510,12 @@ def generate_custom_target(self, target, outfile):
             cmd_type = 'meson_exe.py custom'
         else:
             cmd_type = 'custom'
-
         if target.depfile is not None:
             rel_dfile = os.path.join(self.get_target_dir(target), target.depfile)
             abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target))
             os.makedirs(abs_pdir, exist_ok=True)
             elem.add_item('DEPFILE', rel_dfile)
+        cmd = self.replace_paths(target, cmd)
         elem.add_item('COMMAND', cmd)
         elem.add_item('description', desc.format(target.name, cmd_type))
         elem.write(outfile)
@@ -564,7 +564,9 @@ def generate_run_target(self, target, outfile):
         else:
             cmd.append(target.command)
         cmd += arg_strings
+
         elem.add_dep(deps)
+        cmd = self.replace_paths(target, cmd)
         elem.add_item('COMMAND', cmd)
         elem.add_item('description', 'Running external command %s.' % target.name)
         elem.add_item('pool', 'console')
@@ -1649,6 +1651,16 @@ def generate_generator_list_rules(self, target, outfile):
                 continue
             self.generate_genlist_for_target(genlist, target, outfile)
 
+    def replace_paths(self, target, args):
+        source_target_dir = self.get_target_source_dir(target)
+        relout = self.get_target_private_dir(target)
+        args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout)
+                for x in args]
+        args = [x.replace("@CURRENT_SOURCE_DIR@", source_target_dir) for x in args]
+        args = [x.replace("@SOURCE_ROOT@", self.build_to_src).replace("@BUILD_ROOT@", '.')
+                for x in args]
+        return args
+
     def generate_genlist_for_target(self, genlist, target, outfile):
         generator = genlist.get_generator()
         exe = generator.get_exe()
@@ -1682,11 +1694,7 @@ def generate_genlist_for_target(self, genlist, target, outfile):
             if sole_output == '':
                 outfilelist = outfilelist[len(generator.outputs):]
             relout = self.get_target_private_dir(target)
-            args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout)
-                    for x in args]
-            args = [x.replace("@CURRENT_SOURCE_DIR@", source_target_dir) for x in args]
-            args = [x.replace("@SOURCE_ROOT@", self.build_to_src).replace("@BUILD_ROOT@", '.')
-                    for x in args]
+            args = self.replace_paths(target, args)
             cmdlist = exe_arr + self.replace_extra_args(args, genlist)
             elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename)
             if generator.depfile is not None:


Test patch: