blob: 76daf019b0709278db843d42282116e01ed73a63 [file] [log] [blame]
William A. Kennington IIIac69b482021-06-02 12:28:27 -07001From 4e312c19e693a69b0650ce6c8a8903163c959996 Mon Sep 17 00:00:00 2001
2From: Xavier Claessens <xavier.claessens@collabora.com>
3Date: Tue, 11 May 2021 09:18:47 -0400
4Subject: [PATCH] gnome: Fix gtkdoc generation
5
6install_scripts used to replace @BUILD_ROOT@ and @SOURCE_ROOT@ but it
7was not documented and got removed in Meson 0.58.0. gnome.gtkdoc() was
8relying on that behaviour, but it has always been broken in the case the
9source or build directory contains spaces.
10
11Fix this by changing get_include_args() to substitue paths directly
12which will then get escaped correctly.
13
14Add a unit test that builds GObject documentation which is where this
15issue has been spotted.
16
17Fixes: #8744
18Upstream-Status: Backport
19Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com>
20---
21 mesonbuild/modules/__init__.py | 54 +++++++++----------
22 mesonbuild/modules/gnome.py | 15 +++---
23 mesonbuild/modules/hotdoc.py | 3 +-
24 mesonbuild/modules/qt.py | 4 +-
25 mesonbuild/modules/windows.py | 5 +-
26 .../10 gtk-doc/doc/foobar1/foobar-docs.sgml | 2 +-
27 .../doc/foobar1/foobar-sections.txt | 16 ++++++
28 .../10 gtk-doc/doc/foobar1/foobar.types | 4 ++
29 .../10 gtk-doc/doc/foobar1/meson.build | 6 ++-
30 test cases/frameworks/10 gtk-doc/foo.c | 30 +++++++++++
31 .../frameworks/10 gtk-doc/include/foo.h | 18 +++++++
32 test cases/frameworks/10 gtk-doc/meson.build | 12 +++++
33 test cases/frameworks/10 gtk-doc/test.json | 4 +-
34 13 files changed, 127 insertions(+), 46 deletions(-)
35 create mode 100644 test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-sections.txt
36 create mode 100644 test cases/frameworks/10 gtk-doc/doc/foobar1/foobar.types
37 create mode 100644 test cases/frameworks/10 gtk-doc/foo.c
38
39diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py
40index ddb5e3e6cf3..c0970294c34 100644
41--- a/mesonbuild/modules/__init__.py
42+++ b/mesonbuild/modules/__init__.py
43@@ -56,6 +56,33 @@ def __init__(self, interpreter: 'Interpreter') -> None:
44 self.target_machine = interpreter.builtin['target_machine'].held_object
45 self.current_node = interpreter.current_node
46
47+ def get_include_args(self, include_dirs, prefix='-I'):
48+ if not include_dirs:
49+ return []
50+
51+ srcdir = self.environment.get_source_dir()
52+ builddir = self.environment.get_build_dir()
53+
54+ dirs_str = []
55+ for dirs in unholder(include_dirs):
56+ if isinstance(dirs, str):
57+ dirs_str += [f'{prefix}{dirs}']
58+ continue
59+
60+ # Should be build.IncludeDirs object.
61+ basedir = dirs.get_curdir()
62+ for d in dirs.get_incdirs():
63+ expdir = os.path.join(basedir, d)
64+ srctreedir = os.path.join(srcdir, expdir)
65+ buildtreedir = os.path.join(builddir, expdir)
66+ dirs_str += [f'{prefix}{buildtreedir}',
67+ f'{prefix}{srctreedir}']
68+ for d in dirs.get_extra_build_dirs():
69+ dirs_str += [f'{prefix}{d}']
70+
71+ return dirs_str
72+
73+
74 class ModuleObject:
75 """Base class for all objects returned by modules
76 """
77@@ -71,33 +98,6 @@ def __init__(self, interpreter: T.Optional['Interpreter'] = None) -> None:
78 class ExtensionModule(ModuleObject):
79 pass
80
81-def get_include_args(include_dirs, prefix='-I'):
82- '''
83- Expand include arguments to refer to the source and build dirs
84- by using @SOURCE_ROOT@ and @BUILD_ROOT@ for later substitution
85- '''
86- if not include_dirs:
87- return []
88-
89- dirs_str = []
90- for dirs in unholder(include_dirs):
91- if isinstance(dirs, str):
92- dirs_str += [f'{prefix}{dirs}']
93- continue
94-
95- # Should be build.IncludeDirs object.
96- basedir = dirs.get_curdir()
97- for d in dirs.get_incdirs():
98- expdir = os.path.join(basedir, d)
99- srctreedir = os.path.join('@SOURCE_ROOT@', expdir)
100- buildtreedir = os.path.join('@BUILD_ROOT@', expdir)
101- dirs_str += [f'{prefix}{buildtreedir}',
102- f'{prefix}{srctreedir}']
103- for d in dirs.get_extra_build_dirs():
104- dirs_str += [f'{prefix}{d}']
105-
106- return dirs_str
107-
108 def is_module_library(fname):
109 '''
110 Check if the file is a library-like file generated by a module-specific
111diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
112index d0b053d4f76..c91cda66f8b 100644
113--- a/mesonbuild/modules/gnome.py
114+++ b/mesonbuild/modules/gnome.py
115@@ -26,7 +26,6 @@
116 from .. import mesonlib
117 from .. import interpreter
118 from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget
119-from . import get_include_args
120 from . import ExtensionModule
121 from . import ModuleReturnValue
122 from ..mesonlib import (
123@@ -394,7 +393,7 @@ def _get_dependencies_flags(self, deps, state, depends, include_rpath=False,
124 gi_includes.update([girdir])
125 if isinstance(dep, InternalDependency):
126 cflags.update(dep.get_compile_args())
127- cflags.update(get_include_args(dep.include_directories))
128+ cflags.update(state.get_include_args(dep.include_directories))
129 for lib in unholder(dep.libraries):
130 if isinstance(lib, build.SharedLibrary):
131 internal_ldflags.update(self._get_link_args(state, lib, depends, include_rpath))
132@@ -443,7 +442,7 @@ def _get_dependencies_flags(self, deps, state, depends, include_rpath=False,
133 else:
134 external_ldflags.update([lib])
135 elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
136- cflags.update(get_include_args(dep.get_include_dirs()))
137+ cflags.update(state.get_include_args(dep.get_include_dirs()))
138 depends.append(dep)
139 else:
140 mlog.log(f'dependency {dep!r} not handled to build gir files')
141@@ -853,7 +852,7 @@ def generate_gir(self, state, args, kwargs):
142 scan_command += self._scan_header(kwargs)
143 scan_command += self._scan_extra_args(kwargs)
144 scan_command += ['-I' + srcdir, '-I' + builddir]
145- scan_command += get_include_args(girtargets_inc_dirs)
146+ scan_command += state.get_include_args(girtargets_inc_dirs)
147 scan_command += ['--filelist=' + self._make_gir_filelist(state, srcdir, ns, nsversion, girtargets, libsources)]
148 scan_command += self._scan_link_withs(state, depends, kwargs)
149 scan_command += self._scan_include(state, depends, gir_inc_dirs, kwargs)
150@@ -863,8 +862,8 @@ def generate_gir(self, state, args, kwargs):
151 scan_command += ['--cflags-begin']
152 scan_command += cflags
153 scan_command += ['--cflags-end']
154- scan_command += get_include_args(inc_dirs)
155- scan_command += get_include_args(list(gi_includes) + gir_inc_dirs + inc_dirs, prefix='--add-include-path=')
156+ scan_command += state.get_include_args(inc_dirs)
157+ scan_command += state.get_include_args(list(gi_includes) + gir_inc_dirs + inc_dirs, prefix='--add-include-path=')
158 scan_command += list(internal_ldflags)
159 scan_command += self._scan_gir_targets(state, girtargets)
160 scan_command += self._scan_langs(state, [lc[0] for lc in langs_compilers])
161@@ -886,7 +885,7 @@ def generate_gir(self, state, args, kwargs):
162
163 typelib_output = f'{ns}-{nsversion}.typelib'
164 typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
165- typelib_cmd += get_include_args(gir_inc_dirs, prefix='--includedir=')
166+ typelib_cmd += state.get_include_args(gir_inc_dirs, prefix='--includedir=')
167
168 for incdir in typelib_includes:
169 typelib_cmd += ["--includedir=" + incdir]
170@@ -1127,7 +1126,7 @@ def _get_build_args(self, kwargs, state, depends):
171 'Gir include dirs should be include_directories().')
172
173 cflags.extend(deps_cflags)
174- cflags.extend(get_include_args(inc_dirs))
175+ cflags.extend(state.get_include_args(inc_dirs))
176 ldflags = []
177 ldflags.extend(internal_ldflags)
178 ldflags.extend(external_ldflags)
179diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py
180index bf8cd229c0d..89a5d938ea7 100644
181--- a/mesonbuild/modules/hotdoc.py
182+++ b/mesonbuild/modules/hotdoc.py
183@@ -22,7 +22,6 @@
184 from mesonbuild.coredata import MesonException
185 from . import ModuleReturnValue
186 from . import ExtensionModule
187-from . import get_include_args
188 from ..dependencies import Dependency, InternalDependency
189 from ..interpreterbase import FeatureNew, InvalidArguments, noPosargs, noKwargs
190 from ..interpreter import CustomTargetHolder
191@@ -191,7 +190,7 @@ def process_dependencies(self, deps):
192 for dep in mesonlib.listify(ensure_list(deps)):
193 dep = getattr(dep, "held_object", dep)
194 if isinstance(dep, InternalDependency):
195- inc_args = get_include_args(dep.include_directories)
196+ inc_args = self.state.get_include_args(dep.include_directories)
197 cflags.update([self.replace_dirs_in_string(x)
198 for x in inc_args])
199 cflags.update(self.process_dependencies(dep.libraries))
200diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py
201index b7389bd59af..1bf0099d1df 100644
202--- a/mesonbuild/modules/qt.py
203+++ b/mesonbuild/modules/qt.py
204@@ -23,7 +23,7 @@
205 from ..mesonlib import MesonException, extract_as_list, File, unholder, version_compare
206 from ..dependencies import Dependency
207 import xml.etree.ElementTree as ET
208-from . import ModuleReturnValue, get_include_args, ExtensionModule
209+from . import ModuleReturnValue, ExtensionModule
210 from ..interpreterbase import noPosargs, permittedKwargs, FeatureNew, FeatureNewKwargs
211 from ..interpreter import extract_required_kwarg
212 from ..programs import NonExistingExternalProgram
213@@ -239,7 +239,7 @@ def preprocess(self, state, args, kwargs):
214 ui_gen = build.Generator([self.uic], ui_kwargs)
215 ui_output = ui_gen.process_files(f'Qt{self.qt_version} ui', ui_files, state)
216 sources.append(ui_output)
217- inc = get_include_args(include_dirs=include_directories)
218+ inc = state.get_include_args(include_dirs=include_directories)
219 compile_args = []
220 for dep in unholder(dependencies):
221 if isinstance(dep, Dependency):
222diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
223index d7a86380885..c4fdc196681 100644
224--- a/mesonbuild/modules/windows.py
225+++ b/mesonbuild/modules/windows.py
226@@ -19,7 +19,6 @@
227 from .. import mlog
228 from .. import mesonlib, build
229 from ..mesonlib import MachineChoice, MesonException, extract_as_list, unholder
230-from . import get_include_args
231 from . import ModuleReturnValue
232 from . import ExtensionModule
233 from ..interpreter import CustomTargetHolder
234@@ -83,12 +82,12 @@ def compile_resources(self, state, args, kwargs):
235 wrc_depends = extract_as_list(kwargs, 'depends', pop = True)
236 for d in wrc_depends:
237 if isinstance(d, CustomTargetHolder):
238- extra_args += get_include_args([d.outdir_include()])
239+ extra_args += state.get_include_args([d.outdir_include()])
240 inc_dirs = extract_as_list(kwargs, 'include_directories', pop = True)
241 for incd in inc_dirs:
242 if not isinstance(incd.held_object, (str, build.IncludeDirs)):
243 raise MesonException('Resource include dirs should be include_directories().')
244- extra_args += get_include_args(inc_dirs)
245+ extra_args += state.get_include_args(inc_dirs)
246
247 rescomp, rescomp_type = self._find_resource_compiler(state)
248 if rescomp_type == ResourceCompilerType.rc:
249diff --git a/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml b/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml
250index 95f73efdf45..6ccd087dc18 100644
251--- a/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml
252+++ b/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-docs.sgml
253@@ -35,7 +35,7 @@
254 </partintro>
255 <xi:include href="xml/foo.xml"/>
256 <xi:include href="../../include/bar.xml"/>
257- <xi:include href="xml/foo-version.xml"/>
258+ <xi:include href="xml/version.xml"/>
259 </reference>
260
261 </book>
262diff --git a/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-sections.txt b/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-sections.txt
263new file mode 100644
264index 00000000000..d14c8dab010
265--- /dev/null
266+++ b/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar-sections.txt
267@@ -0,0 +1,16 @@
268+<SECTION>
269+<FILE>foo</FILE>
270+<TITLE>FooObj</TITLE>
271+FooObj
272+FooObjClass
273+foo_do_something
274+</SECTION>
275+
276+<SECTION>
277+<FILE>version</FILE>
278+<TITLE>version</TITLE>
279+FOO_MAJOR_VERSION
280+FOO_MINOR_VERSION
281+FOO_MICRO_VERSION
282+</SECTION>
283+
284diff --git a/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar.types b/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar.types
285new file mode 100644
286index 00000000000..0a9c046f3ed
287--- /dev/null
288+++ b/test cases/frameworks/10 gtk-doc/doc/foobar1/foobar.types
289@@ -0,0 +1,4 @@
290+% This include is useless it's a regression test for https://github.com/mesonbuild/meson/issues/8744
291+#include <foo.h>
292+
293+foo_obj_get_type
294diff --git a/test cases/frameworks/10 gtk-doc/doc/foobar1/meson.build b/test cases/frameworks/10 gtk-doc/doc/foobar1/meson.build
295index 149c6e956aa..f4b3724dbae 100644
296--- a/test cases/frameworks/10 gtk-doc/doc/foobar1/meson.build
297+++ b/test cases/frameworks/10 gtk-doc/doc/foobar1/meson.build
298@@ -1,5 +1,9 @@
299 gnome.gtkdoc('foobar',
300- src_dir : inc,
301+ src_dir : [inc, '.'],
302 main_sgml : 'foobar-docs.sgml',
303 content_files : [docbook, version_xml],
304+ dependencies: foo_dep,
305+ # Manually written types file for regression test:
306+ # https://github.com/mesonbuild/meson/issues/8744
307+ gobject_typesfile: 'foobar.types',
308 install : true)
309diff --git a/test cases/frameworks/10 gtk-doc/foo.c b/test cases/frameworks/10 gtk-doc/foo.c
310new file mode 100644
311index 00000000000..36c0639ec08
312--- /dev/null
313+++ b/test cases/frameworks/10 gtk-doc/foo.c
314@@ -0,0 +1,30 @@
315+#include <foo.h>
316+
317+
318+struct _FooObj {
319+ GObject parent;
320+ int dummy;
321+};
322+
323+G_DEFINE_TYPE(FooObj, foo_obj, G_TYPE_OBJECT)
324+
325+static void foo_obj_init (FooObj *self)
326+{
327+}
328+
329+static void foo_obj_class_init (FooObjClass *klass)
330+{
331+}
332+
333+/**
334+ * foo_do_something:
335+ * @self: self
336+ *
337+ * Useless function.
338+ *
339+ * Returns: 0.
340+ */
341+int foo_do_something(FooObj *self)
342+{
343+ return 0;
344+}
345diff --git a/test cases/frameworks/10 gtk-doc/include/foo.h b/test cases/frameworks/10 gtk-doc/include/foo.h
346index 7b8946b6a86..510f3d1ecb5 100644
347--- a/test cases/frameworks/10 gtk-doc/include/foo.h
348+++ b/test cases/frameworks/10 gtk-doc/include/foo.h
349@@ -1,5 +1,7 @@
350 #pragma once
351
352+#include <glib-object.h>
353+
354 /**
355 * FooIndecision:
356 * @FOO_MAYBE: Something maybe
357@@ -13,3 +15,19 @@ typedef enum {
358 FOO_POSSIBLY,
359 } FooIndecision;
360
361+/**
362+ * FooObjClass:
363+ *
364+ * The class
365+ */
366+
367+/**
368+ * FooObj:
369+ *
370+ * The instance
371+ */
372+
373+#define FOO_TYPE_OBJ foo_obj_get_type()
374+G_DECLARE_FINAL_TYPE(FooObj, foo_obj, FOO, OBJ, GObject)
375+
376+int foo_do_something(FooObj *self);
377diff --git a/test cases/frameworks/10 gtk-doc/meson.build b/test cases/frameworks/10 gtk-doc/meson.build
378index 5c22ad0afa4..292980fafa7 100644
379--- a/test cases/frameworks/10 gtk-doc/meson.build
380+++ b/test cases/frameworks/10 gtk-doc/meson.build
381@@ -24,4 +24,16 @@ if gtkdoc_ver.version_compare('<1.26')
382 error('MESON_SKIP_TEST gtk-doc test requires gtkdoc >= 1.26.')
383 endif
384
385+gobject = dependency('gobject-2.0')
386+
387+libfoo = library('foo', 'foo.c',
388+ include_directories: inc,
389+ dependencies: gobject,
390+)
391+
392+foo_dep = declare_dependency(
393+ link_with: libfoo,
394+ include_directories: inc,
395+)
396+
397 subdir('doc')
398diff --git a/test cases/frameworks/10 gtk-doc/test.json b/test cases/frameworks/10 gtk-doc/test.json
399index c44126cc741..03ad0595817 100644
400--- a/test cases/frameworks/10 gtk-doc/test.json
401+++ b/test cases/frameworks/10 gtk-doc/test.json
402@@ -4,8 +4,8 @@
403 {"type": "file", "file": "usr/share/gtk-doc/html/foobar/BAR.html"},
404 {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foobar.devhelp2"},
405 {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foobar.html"},
406- {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foobar-foo.html"},
407- {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foobar-foo-version.html"},
408+ {"type": "file", "file": "usr/share/gtk-doc/html/foobar/FooObj.html"},
409+ {"type": "file", "file": "usr/share/gtk-doc/html/foobar/foo-version.html"},
410 {"type": "file", "file": "usr/share/gtk-doc/html/foobar/home.png"},
411 {"type": "file", "file": "usr/share/gtk-doc/html/foobar/index.html"},
412 {"type": "file", "file": "usr/share/gtk-doc/html/foobar/left.png"},