From 6ea939dd5fb1401f87b57f72e1479aab3382069c Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 9 Aug 2018 17:34:55 +0200 Subject: [PATCH] gnome.generate_gir: support generating gir for multiple libraries Fixes #3688 --- docs/markdown/Gnome-module.md | 13 +- .../generate_gir_multiple_libraries.md | 7 ++ mesonbuild/modules/gnome.py | 119 +++++++++++------- .../frameworks/7 gnome/gir/meson-sample2.c | 45 +++++++ .../frameworks/7 gnome/gir/meson-sample2.h | 21 ++++ test cases/frameworks/7 gnome/gir/meson.build | 12 +- test cases/frameworks/7 gnome/gir/prog.py | 3 + 7 files changed, 167 insertions(+), 53 deletions(-) create mode 100644 docs/markdown/snippets/generate_gir_multiple_libraries.md create mode 100644 test cases/frameworks/7 gnome/gir/meson-sample2.c create mode 100644 test cases/frameworks/7 gnome/gir/meson-sample2.h diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md index 6b63f8a63..cc85d87d0 100644 --- a/docs/markdown/Gnome-module.md +++ b/docs/markdown/Gnome-module.md @@ -67,10 +67,15 @@ executable( ### gnome.generate_gir() -Generates GObject introspection data. Takes one positional argument, -the build target you want to build gir data for. There are several -keyword arguments. Many of these map directly to the `g-ir-scanner` -tool so see its documentation for more information. +Generates GObject introspection data. + +Takes one or more positional arguments: + +Either one or more library objects you want to build gir data for, or a single +executable object. + +There are several keyword arguments. Many of these map directly to the +`g-ir-scanner` tool so see its documentation for more information. * `dependencies`: deps to use during introspection scanning * `extra_args`: command line arguments to pass to gir compiler diff --git a/docs/markdown/snippets/generate_gir_multiple_libraries.md b/docs/markdown/snippets/generate_gir_multiple_libraries.md new file mode 100644 index 000000000..3541b7110 --- /dev/null +++ b/docs/markdown/snippets/generate_gir_multiple_libraries.md @@ -0,0 +1,7 @@ +## gnome.generate_gir() now optionally accepts multiple libraries + +The GNOME module can now generate a single gir for multiple libraries, which +is something `g-ir-scanner` supported, but had not been exposed yet. + +gnome.generate_gir() will now accept multiple positional arguments, if none +of these arguments are an `Executable` instance. diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index f22ad1e61..34dcbe89b 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -499,54 +499,69 @@ class GnomeModule(ExtensionModule): 'Gir include dirs should be include_directories().') return ret - def _scan_lang(self, state, lang): + def _scan_langs(self, state, langs): ret = [] - for link_arg in state.environment.coredata.get_external_link_args(lang): - if link_arg.startswith('-L'): - ret.append(link_arg) + for lang in langs: + for link_arg in state.environment.coredata.get_external_link_args(lang): + if link_arg.startswith('-L'): + ret.append(link_arg) return ret - def _scan_gir_target(self, state, girtarget): + def _scan_gir_targets(self, state, girtargets): ret = [] - if isinstance(girtarget, build.Executable): - ret += ['--program', girtarget] - elif isinstance(girtarget, build.SharedLibrary): - libname = girtarget.get_basename() - # Needed for the following binutils bug: - # https://github.com/mesonbuild/meson/issues/1911 - # However, g-ir-scanner does not understand -Wl,-rpath - # so we need to use -L instead - for d in state.backend.determine_rpath_dirs(girtarget): - d = os.path.join(state.environment.get_build_dir(), d) - ret.append('-L' + d) - ret += ['--library', libname] - # need to put our output directory first as we need to use the - # generated libraries instead of any possibly installed system/prefix - # ones. - ret += ["-L@PRIVATE_OUTDIR_ABS_%s@" % girtarget.get_id()] + for girtarget in girtargets: + if isinstance(girtarget, build.Executable): + ret += ['--program', girtarget] + elif isinstance(girtarget, build.SharedLibrary): + libname = girtarget.get_basename() + # Needed for the following binutils bug: + # https://github.com/mesonbuild/meson/issues/1911 + # However, g-ir-scanner does not understand -Wl,-rpath + # so we need to use -L instead + for d in state.backend.determine_rpath_dirs(girtarget): + d = os.path.join(state.environment.get_build_dir(), d) + ret.append('-L' + d) + ret += ['--library', libname] + # need to put our output directory first as we need to use the + # generated libraries instead of any possibly installed system/prefix + # ones. + ret += ["-L@PRIVATE_OUTDIR_ABS_%s@" % girtarget.get_id()] return ret - def _get_girtarget_lang_compiler(self, girtarget): - for lang, compiler in girtarget.compilers.items(): - # XXX: Can you use g-i with any other language? - if lang in ('c', 'cpp', 'objc', 'objcpp', 'd'): - break - else: - lang = None - compiler = None + def _get_girtargets_langs_compilers(self, girtargets): + ret = [] + for girtarget in girtargets: + for lang, compiler in girtarget.compilers.items(): + # XXX: Can you use g-i with any other language? + if lang in ('c', 'cpp', 'objc', 'objcpp', 'd'): + ret.append((lang, compiler)) + break + + return ret - return lang, compiler + def _get_gir_targets_deps(self, girtargets): + ret = [] + for girtarget in girtargets: + ret += girtarget.get_all_link_deps() + ret += girtarget.get_external_deps() + return ret + + def _get_gir_targets_inc_dirs(self, girtargets): + ret = [] + for girtarget in girtargets: + ret += girtarget.get_include_dirs() + return ret - def _get_lang_compiler_flags(self, state, lang, compiler): + def _get_langs_compilers_flags(self, state, langs_compilers): cflags = [] internal_ldflags = [] external_ldflags = [] - if lang and compiler: + for lang, compiler in langs_compilers: if state.global_args.get(lang): cflags += state.global_args[lang] if state.project_args.get(lang): @@ -562,8 +577,8 @@ class GnomeModule(ExtensionModule): return cflags, internal_ldflags, external_ldflags - def _make_gir_filelist(self, state, srcdir, ns, nsversion, girtarget, libsources): - gir_filelist_dir = state.backend.get_target_private_dir_abs(girtarget) + def _make_gir_filelist(self, state, srcdir, ns, nsversion, girtargets, libsources): + gir_filelist_dir = state.backend.get_target_private_dir_abs(girtargets[0]) if not os.path.isdir(gir_filelist_dir): os.mkdir(gir_filelist_dir) gir_filelist_filename = os.path.join(gir_filelist_dir, '%s_%s_gir_filelist' % (ns, nsversion)) @@ -658,21 +673,30 @@ class GnomeModule(ExtensionModule): return typelib_includes + def _get_external_args_for_langs(self, state, langs): + ret = [] + for lang in langs: + ret += state.environment.coredata.get_external_args(lang) + return ret + @FeatureNewKwargs('build target', '0.40.0', ['build_by_default']) @permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', 'export_packages', 'includes', 'dependencies', 'link_with', 'include_directories', 'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args', 'packages', 'header', 'build_by_default'}) def generate_gir(self, state, args, kwargs): - if len(args) != 1: - raise MesonException('Gir takes one argument') + if not args: + raise MesonException('generate_gir takes at least one argument') if kwargs.get('install_dir'): raise MesonException('install_dir is not supported with generate_gir(), see "install_dir_gir" and "install_dir_typelib"') giscanner = self.interpreter.find_program_impl('g-ir-scanner') gicompiler = self.interpreter.find_program_impl('g-ir-compiler') - girtarget = self._unwrap_gir_target(args[0]) + girtargets = [self._unwrap_gir_target(arg) for arg in args] + + if len(girtargets) > 1 and any([isinstance(el, build.Executable) for el in girtargets]): + raise MesonException('generate_gir only accepts a single argument when one of the arguments is an executable') self.gir_dep, pkgargs = self._get_gir_dep(state) @@ -682,12 +706,12 @@ class GnomeModule(ExtensionModule): girfile = '%s-%s.gir' % (ns, nsversion) srcdir = os.path.join(state.environment.get_source_dir(), state.subdir) builddir = os.path.join(state.environment.get_build_dir(), state.subdir) - depends = [girtarget] + depends = [] + girtargets gir_inc_dirs = [] - lang, compiler = self._get_girtarget_lang_compiler(girtarget) - cflags, internal_ldflags, external_ldflags = self._get_lang_compiler_flags(state, lang, compiler) - deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() + - extract_as_list(kwargs, 'dependencies', pop=True, unholder=True)) + langs_compilers = self._get_girtargets_langs_compilers(girtargets) + cflags, internal_ldflags, external_ldflags = self._get_langs_compilers_flags(state, langs_compilers) + deps = self._get_gir_targets_deps(girtargets) + deps += extract_as_list(kwargs, 'dependencies', pop=True, unholder=True) typelib_includes = self._gather_typelib_includes_and_update_depends(state, deps, depends) # ldflags will be misinterpreted by gir scanner (showing # spurious dependencies) but building GStreamer fails if they @@ -697,6 +721,7 @@ class GnomeModule(ExtensionModule): cflags += list(dep_cflags) internal_ldflags += list(dep_internal_ldflags) external_ldflags += list(dep_external_ldflags) + girtargets_inc_dirs = self._get_gir_targets_inc_dirs(girtargets) inc_dirs = self._scan_inc_dirs(kwargs) scan_command = [giscanner] @@ -708,8 +733,8 @@ class GnomeModule(ExtensionModule): scan_command += self._scan_header(kwargs) scan_command += self._scan_extra_args(kwargs) scan_command += ['-I' + srcdir, '-I' + builddir] - scan_command += get_include_args(girtarget.get_include_dirs()) - scan_command += ['--filelist=' + self._make_gir_filelist(state, srcdir, ns, nsversion, girtarget, libsources)] + scan_command += get_include_args(girtargets_inc_dirs) + scan_command += ['--filelist=' + self._make_gir_filelist(state, srcdir, ns, nsversion, girtargets, libsources)] scan_command += self._scan_link_withs(state, depends, kwargs) scan_command += self._scan_include(state, depends, gir_inc_dirs, kwargs) scan_command += self._scan_symbol_prefix(kwargs) @@ -717,12 +742,12 @@ class GnomeModule(ExtensionModule): scan_command += self._scan_export_packages(kwargs) scan_command += ['--cflags-begin'] scan_command += cflags - scan_command += state.environment.coredata.get_external_args(lang) + scan_command += self._get_external_args_for_langs(state, [lc[0] for lc in langs_compilers]) scan_command += ['--cflags-end'] scan_command += get_include_args(inc_dirs) scan_command += get_include_args(list(gi_includes) + gir_inc_dirs + inc_dirs, prefix='--add-include-path=') - scan_command += self._scan_gir_target(state, girtarget) - scan_command += self._scan_lang(state, lang) + scan_command += self._scan_gir_targets(state, girtargets) + scan_command += self._scan_langs(state, [lc[0] for lc in langs_compilers]) scan_command += list(internal_ldflags) scan_command += list(external_ldflags) diff --git a/test cases/frameworks/7 gnome/gir/meson-sample2.c b/test cases/frameworks/7 gnome/gir/meson-sample2.c new file mode 100644 index 000000000..f76bc1629 --- /dev/null +++ b/test cases/frameworks/7 gnome/gir/meson-sample2.c @@ -0,0 +1,45 @@ +#include "meson-sample2.h" + +struct _MesonSample2 +{ + GObject parent_instance; +}; + +G_DEFINE_TYPE (MesonSample2, meson_sample2, G_TYPE_OBJECT) + +/** + * meson_sample2_new: + * + * Allocates a new #MesonSample2. + * + * Returns: (transfer full): a #MesonSample2. + */ +MesonSample2 * +meson_sample2_new (void) +{ + return g_object_new (MESON_TYPE_SAMPLE2, NULL); +} + +static void +meson_sample2_class_init (MesonSample2Class *klass) +{ +} + +static void +meson_sample2_init (MesonSample2 *self) +{ +} + +/** + * meson_sample2_print_message: + * @self: a #MesonSample2. + * + * Prints Hello. + * + * Returns: Nothing. + */ +void +meson_sample2_print_message (MesonSample2 *self) +{ + g_print ("Message: Hello\n"); +} diff --git a/test cases/frameworks/7 gnome/gir/meson-sample2.h b/test cases/frameworks/7 gnome/gir/meson-sample2.h new file mode 100644 index 000000000..d39084ebe --- /dev/null +++ b/test cases/frameworks/7 gnome/gir/meson-sample2.h @@ -0,0 +1,21 @@ +#ifndef MESON_SAMPLE2_H +#define MESON_SAMPLE2_H + +#if !defined (MESON_TEST) +#error "MESON_TEST not defined." +#endif + +#include + +G_BEGIN_DECLS + +#define MESON_TYPE_SAMPLE2 (meson_sample2_get_type()) + +G_DECLARE_FINAL_TYPE (MesonSample2, meson_sample2, MESON, SAMPLE2, GObject) + +MesonSample2 *meson_sample2_new (void); +void meson_sample2_print_message (MesonSample2 *self); + +G_END_DECLS + +#endif /* MESON_SAMPLE2_H */ diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build index 177154826..36bd09c51 100644 --- a/test cases/frameworks/7 gnome/gir/meson.build +++ b/test cases/frameworks/7 gnome/gir/meson.build @@ -1,6 +1,7 @@ subdir('dep1') libsources = ['meson-sample.c', 'meson-sample.h'] +lib2sources = ['meson-sample2.c', 'meson-sample2.h'] girlib = shared_library( 'gir_lib', @@ -9,6 +10,13 @@ girlib = shared_library( install : true ) +girlib2 = shared_library( + 'gir_lib2', + sources : lib2sources, + dependencies : [gobj], + install : true +) + girexe = executable( 'girprog', sources : 'prog.c', @@ -19,8 +27,8 @@ girexe = executable( fake_dep = dependency('no-way-this-exists', required: false) gnome.generate_gir( - girlib, - sources : libsources, + girlib, girlib2, + sources : libsources + lib2sources, nsversion : '1.0', namespace : 'Meson', symbol_prefix : 'meson', diff --git a/test cases/frameworks/7 gnome/gir/prog.py b/test cases/frameworks/7 gnome/gir/prog.py index 7ce2aa724..aa1f9a774 100755 --- a/test cases/frameworks/7 gnome/gir/prog.py +++ b/test cases/frameworks/7 gnome/gir/prog.py @@ -6,3 +6,6 @@ if __name__ == "__main__": dep1 = MesonDep1.Dep1.new() dep2 = MesonDep2.Dep2.new("Hello, meson/py!") s.print_message(dep1, dep2) + + s2 = Meson.Sample2.new() + s2.print_message()