From 52a4b3302e17654ef18a2e439ca9e6353f323254 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Sep 2016 12:30:44 -0300 Subject: [PATCH 1/4] gnome: Make all include paths absolute The relative computation was broken when using subprojects. --- mesonbuild/modules/gnome.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 4f72d2f17..7d15578b2 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -107,8 +107,6 @@ class GnomeModule: if not include_dirs: return [] - build_to_src = os.path.relpath(state.environment.get_source_dir(), - state.environment.get_build_dir()) dirs_str = [] for incdirs in include_dirs: if hasattr(incdirs, "held_object"): @@ -124,8 +122,9 @@ class GnomeModule: basedir = dirs.get_curdir() for d in dirs.get_incdirs(): expdir = os.path.join(basedir, d) - srctreedir = os.path.join(build_to_src, expdir) - dirs_str += ['%s%s' % (prefix, expdir), + srctreedir = os.path.join(state.environment.get_source_dir(), expdir) + buildtreedir = os.path.join(state.environment.get_build_dir(), expdir) + dirs_str += ['%s%s' % (prefix, buildtreedir), '%s%s' % (prefix, srctreedir)] for d in dirs.get_extra_build_dirs(): dirs_str += ['%s%s' % (prefix, d)] From 68ae8e1ad008236ffb4d85dfa37f4eb2eb6c7cb3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Sep 2016 12:31:59 -0300 Subject: [PATCH 2/4] gnome: Factor out a get_dependencies_flags method And recurse to make sure that we build against all internal dependencies dependencies. --- mesonbuild/modules/gnome.py | 107 ++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 7d15578b2..0b30d6d1d 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -131,6 +131,63 @@ class GnomeModule: return dirs_str + def get_dependencies_flags(self, deps, state, depends=None): + cflags = set() + ldflags = set() + gi_includes = set() + if not isinstance(deps, list): + deps = [deps] + + for dep in deps: + if hasattr(dep, 'held_object'): + dep = dep.held_object + if isinstance(dep, dependencies.InternalDependency): + cflags.update(self.get_include_args( state, dep.include_directories)) + for lib in dep.libraries: + ldflags.update(self.get_link_args(state, lib.held_object, depends)) + libdepflags = self.get_dependencies_flags(lib.held_object.get_external_deps(), state, depends) + cflags.update(libdepflags[0]) + ldflags.update(libdepflags[1]) + gi_includes.update(libdepflags[2]) + extdepflags = self.get_dependencies_flags(dep.ext_deps, state, depends) + cflags.update(extdepflags[0]) + ldflags.update(extdepflags[1]) + gi_includes.update(extdepflags[2]) + for source in dep.sources: + if isinstance(source.held_object, GirTarget): + gi_includes.update([os.path.join(state.environment.get_build_dir(), + source.held_object.get_subdir())]) + # This should be any dependency other than an internal one. + elif isinstance(dep, dependencies.Dependency): + cflags.update(dep.get_compile_args()) + for lib in dep.get_link_args(): + if (os.path.isabs(lib) and + # For PkgConfigDependency only: + getattr(dep, 'is_libtool', False)): + ldflags.update(["-L%s" % os.path.dirname(lib)]) + libname = os.path.basename(lib) + if libname.startswith("lib"): + libname = libname[3:] + libname = libname.split(".so")[0] + lib = "-l%s" % libname + # Hack to avoid passing some compiler options in + if lib.startswith("-W"): + continue + ldflags.update([lib]) + + if isinstance(dep, dependencies.PkgConfigDependency): + girdir = dep.get_variable("girdir") + if girdir: + gi_includes.update([girdir]) + elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): + for incd in dep.get_include_dirs(): + cflags.update(incd.get_incdirs()) + else: + mlog.log('dependency %s not handled to build gir files' % dep) + continue + + return cflags, ldflags, gi_includes + def generate_gir(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gir takes one argument') @@ -220,52 +277,10 @@ class GnomeModule: deps = [deps] deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() + deps) - for dep in deps: - if hasattr(dep, 'held_object'): - dep = dep.held_object - if isinstance(dep, dependencies.InternalDependency): - scan_command += self.get_include_args( - state, - dep.include_directories) - for lib in dep.libraries: - scan_command += self.get_link_args(state, lib.held_object, - depends) - for source in dep.sources: - if isinstance(source.held_object, GirTarget): - scan_command += [ - "--add-include-path=%s" % ( - os.path.join(state.environment.get_build_dir(), - source.held_object.get_subdir()), - ) - ] - # This should be any dependency other than an internal one. - elif isinstance(dep, dependencies.Dependency): - scan_command += dep.get_compile_args() - for lib in dep.get_link_args(): - if (os.path.isabs(lib) and - # For PkgConfigDependency only: - getattr(dep, 'is_libtool', False)): - scan_command += ["-L%s" % os.path.dirname(lib)] - libname = os.path.basename(lib) - if libname.startswith("lib"): - libname = libname[3:] - libname = libname.split(".so")[0] - lib = "-l%s" % libname - # Hack to avoid passing some compiler options in - if lib.startswith("-W"): - continue - scan_command += [lib] - - if isinstance(dep, dependencies.PkgConfigDependency): - girdir = dep.get_variable("girdir") - if girdir: - scan_command += ["--add-include-path=%s" % (girdir, )] - elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): - for incd in dep.get_include_dirs(): - scan_command += incd.get_incdirs() - else: - mlog.log('dependency %s not handled to build gir files' % dep) - continue + cflags, ldflags, gi_includes = self.get_dependencies_flags(deps, state, depends) + scan_command += list(cflags) + list(ldflags) + for i in gi_includes: + scan_command += ['--add-include-path=%s' % i] inc_dirs = kwargs.pop('include_directories', []) if not isinstance(inc_dirs, list): From f86fbf6ebf68081d2949333ed6bfcda7f768d149 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Sep 2016 20:22:52 -0300 Subject: [PATCH 3/4] gnome: Run gtkdoc-scanobjs and add a way to get assets working Allowing the object tree to be generated. We need to add options to allow copying the ncesseary sources and assets so the HTML generator can work with them (everything is relative so we need to copy them in the build directory). Until now the documentation was not generated from the user provided main sgml file but it was using a generated one, which lead to a broken documentation. Starting using it revealed the other bugs fixed in that commit. --- mesonbuild/modules/gnome.py | 64 +++++++++++++++++------ mesonbuild/scripts/gtkdochelper.py | 84 ++++++++++++++++++++++++------ 2 files changed, 116 insertions(+), 32 deletions(-) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 0b30d6d1d..cec0c696c 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -16,7 +16,7 @@ functionality such as gobject-introspection and gresources.''' from .. import build -import os, sys +import os import subprocess from ..mesonlib import MesonException from .. import dependencies @@ -94,13 +94,14 @@ class GnomeModule: return stdout.split('\n')[:-1] - def get_link_args(self, state, lib, depends): + def get_link_args(self, state, lib, depends=None): link_command = ['-l%s' % lib.name] if isinstance(lib, build.SharedLibrary): link_command += ['-L%s' % os.path.join(state.environment.get_build_dir(), lib.subdir)] - depends.append(lib) + if depends: + depends.append(lib) return link_command def get_include_args(self, state, include_dirs, prefix='-I'): @@ -391,12 +392,39 @@ class GnomeModule: '--modulename=' + modulename] args += self.unpack_args('--htmlargs=', 'html_args', kwargs) args += self.unpack_args('--scanargs=', 'scan_args', kwargs) + args += self.unpack_args('--scanobjsargs=', 'scanobjs_args', kwargs) + args += self.unpack_args('--gobjects-types-file=', 'gobject_typesfile', kwargs, state) args += self.unpack_args('--fixxrefargs=', 'fixxref_args', kwargs) + args += self.unpack_args('--html-assets=', 'html_assets', kwargs, state) + args += self.unpack_args('--content-files=', 'content_files', kwargs, state) + args += self.get_build_args(kwargs, state) res = [build.RunTarget(targetname, command[0], command[1:] + args, [], state.subdir)] if kwargs.get('install', True): res.append(build.InstallScript(command + args)) return res + def get_build_args(self, kwargs, state): + args = [] + cflags, ldflags, gi_includes = self.get_dependencies_flags(kwargs.get('dependencies', []), state) + inc_dirs = kwargs.get('include_directories', []) + if not isinstance(inc_dirs, list): + inc_dirs = [inc_dirs] + for incd in inc_dirs: + if not isinstance(incd.held_object, (str, build.IncludeDirs)): + raise MesonException( + 'Gir include dirs should be include_directories().') + cflags.update(self.get_include_args(state, inc_dirs)) + if cflags: + args += ['--cflags=%s' % ' '.join(cflags)] + if ldflags: + args += ['--ldflags=%s' % ' '.join(ldflags)] + compiler = state.environment.coredata.compilers.get('c') + if compiler: + args += ['--cc=%s' % ' '.join(compiler.get_exelist())] + args += ['--ld=%s' % ' '.join(compiler.get_linker_exelist())] + + return args + def gtkdoc_html_dir(self, state, args, kwarga): if len(args) != 1: raise MesonException('Must have exactly one argument.') @@ -406,18 +434,24 @@ class GnomeModule: return os.path.join('share/gtkdoc/html', modulename) - def unpack_args(self, arg, kwarg_name, kwargs): - try: - new_args = kwargs[kwarg_name] - if not isinstance(new_args, list): - new_args = [new_args] - for i in new_args: - if not isinstance(i, str): - raise MesonException('html_args values must be strings.') - except KeyError: - return[] - if len(new_args) > 0: - return [arg + '@@'.join(new_args)] + def unpack_args(self, arg, kwarg_name, kwargs, expend_file_state=None): + if kwarg_name not in kwargs: + return [] + + new_args = kwargs[kwarg_name] + if not isinstance(new_args, list): + new_args = [new_args] + args = [] + for i in new_args: + if expend_file_state and isinstance(i, mesonlib.File): + i = os.path.join(expend_file_state.environment.get_build_dir(), i.subdir, i.fname) + elif not isinstance(i, str): + raise MesonException(kwarg_name + ' values must be strings.') + args.append(i) + + if args: + return [arg + '@@'.join(args)] + return [] def gdbus_codegen(self, state, args, kwargs): diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py index 0c87717ce..18a7597af 100644 --- a/mesonbuild/scripts/gtkdochelper.py +++ b/mesonbuild/scripts/gtkdochelper.py @@ -30,7 +30,15 @@ parser.add_argument('--mainfile', dest='mainfile') parser.add_argument('--modulename', dest='modulename') parser.add_argument('--htmlargs', dest='htmlargs', default='') parser.add_argument('--scanargs', dest='scanargs', default='') +parser.add_argument('--scanobjsargs', dest='scanobjsargs', default='') +parser.add_argument('--gobjects-types-file', dest='gobject_typesfile', default='') parser.add_argument('--fixxrefargs', dest='fixxrefargs', default='') +parser.add_argument('--ld', dest='ld', default='') +parser.add_argument('--cc', dest='cc', default='') +parser.add_argument('--ldflags', dest='ldflags', default='') +parser.add_argument('--cflags', dest='cflags', default='') +parser.add_argument('--content-files', dest='content_files', default='') +parser.add_argument('--html-assets', dest='html_assets', default='') def gtkdoc_run_check(cmd, cwd): p = subprocess.Popen(cmd, cwd=cwd, @@ -45,15 +53,49 @@ def gtkdoc_run_check(cmd, cwd): raise MesonException('\n'.join(err_msg)) def build_gtkdoc(source_root, build_root, doc_subdir, src_subdir, - main_file, module, html_args, scan_args, fixxref_args): + main_file, module, html_args, scan_args, fixxref_args, + gobject_typesfile, scanobjs_args, ld, cc, ldflags, cflags, + html_assets, content_files): + print("Building documentation for %s" % module) + abs_src = os.path.join(source_root, src_subdir) + doc_src = os.path.join(source_root, doc_subdir) abs_out = os.path.join(build_root, doc_subdir) htmldir = os.path.join(abs_out, 'html') + + content_files += [main_file] + sections = os.path.join(doc_src, module + "-sections.txt") + if os.path.exists(sections): + content_files.append(sections) + + # Copy files to build directory + for f in content_files: + f_abs = os.path.join(doc_src, f) + shutil.copyfile(f_abs, os.path.join( + abs_out, os.path.basename(f_abs))) + + shutil.rmtree(htmldir, ignore_errors=True) + try: + os.mkdir(htmldir) + except Exception: + pass + + for f in html_assets: + f_abs = os.path.join(doc_src, f) + shutil.copyfile(f_abs, os.path.join(htmldir, os.path.basename(f_abs))) + scan_cmd = ['gtkdoc-scan', '--module=' + module, '--source-dir=' + abs_src] + scan_args gtkdoc_run_check(scan_cmd, abs_out) + if gobject_typesfile: + scanobjs_cmd = ['gtkdoc-scangobj'] + scanobjs_args + [gobject_typesfile, + '--module=' + module, '--cflags=' + cflags, '--ldflags=' + ldflags] + + gtkdoc_run_check(scanobjs_cmd, abs_out) + + # Make docbook files if main_file.endswith('sgml'): modeflag = '--sgml-mode' @@ -62,21 +104,16 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdir, mkdb_cmd = ['gtkdoc-mkdb', '--module=' + module, '--output-format=xml', + '--expand-content-files=', modeflag, '--source-dir=' + abs_src] - main_abs = os.path.join(source_root, doc_subdir, main_file) if len(main_file) > 0: # Yes, this is the flag even if the file is in xml. mkdb_cmd.append('--main-sgml-file=' + main_file) gtkdoc_run_check(mkdb_cmd, abs_out) # Make HTML documentation - shutil.rmtree(htmldir, ignore_errors=True) - try: - os.mkdir(htmldir) - except Exception: - pass - mkhtml_cmd = ['gtkdoc-mkhtml', + mkhtml_cmd = ['gtkdoc-mkhtml', '--path=' + abs_src, module, ] + html_args @@ -109,19 +146,32 @@ def run(args): scanargs = options.scanargs.split('@@') else: scanargs = [] + if len(options.scanobjsargs) > 0: + scanobjsargs = options.scanobjsargs.split('@@') + else: + scanobjsargs = [] if len(options.fixxrefargs) > 0: fixxrefargs = options.fixxrefargs.split('@@') else: fixxrefargs = [] - build_gtkdoc(options.sourcedir, - options.builddir, - options.subdir, - options.headerdir, - options.mainfile, - options.modulename, - htmlargs, - scanargs, - fixxrefargs) + build_gtkdoc( + options.sourcedir, + options.builddir, + options.subdir, + options.headerdir, + options.mainfile, + options.modulename, + htmlargs, + scanargs, + fixxrefargs, + options.gobject_typesfile, + scanobjsargs, + options.ld, + options.cc, + options.ldflags, + options.cflags, + options.html_assets.split('@@') if options.html_assets else [], + options.content_files.split('@@') if options.content_files else []) if 'MESON_INSTALL_PREFIX' in os.environ: destdir = os.environ.get('DESTDIR', '') From bb3823e6f4f8332be25d33e07af0d6059f304d51 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 24 Sep 2016 12:05:58 -0300 Subject: [PATCH 4/4] gnome: Allow specifying gtkdoc where to install directory --- mesonbuild/modules/gnome.py | 1 + mesonbuild/scripts/gtkdochelper.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index cec0c696c..11abf8815 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -397,6 +397,7 @@ class GnomeModule: args += self.unpack_args('--fixxrefargs=', 'fixxref_args', kwargs) args += self.unpack_args('--html-assets=', 'html_assets', kwargs, state) args += self.unpack_args('--content-files=', 'content_files', kwargs, state) + args += self.unpack_args('--installdir=', 'install_dir', kwargs, state) args += self.get_build_args(kwargs, state) res = [build.RunTarget(targetname, command[0], command[1:] + args, [], state.subdir)] if kwargs.get('install', True): diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py index 18a7597af..e87a37917 100644 --- a/mesonbuild/scripts/gtkdochelper.py +++ b/mesonbuild/scripts/gtkdochelper.py @@ -39,6 +39,7 @@ parser.add_argument('--ldflags', dest='ldflags', default='') parser.add_argument('--cflags', dest='cflags', default='') parser.add_argument('--content-files', dest='content_files', default='') parser.add_argument('--html-assets', dest='html_assets', default='') +parser.add_argument('--installdir', dest='install_dir') def gtkdoc_run_check(cmd, cwd): p = subprocess.Popen(cmd, cwd=cwd, @@ -174,13 +175,14 @@ def run(args): options.content_files.split('@@') if options.content_files else []) if 'MESON_INSTALL_PREFIX' in os.environ: + install_dir = options.install_dir if options.install_dir else options.modulename destdir = os.environ.get('DESTDIR', '') installdir = destdir_join(destdir, os.environ['MESON_INSTALL_PREFIX']) install_gtkdoc(options.builddir, options.subdir, installdir, 'share/gtk-doc/html', - options.modulename) + install_dir) return 0 if __name__ == '__main__':