summaryrefslogtreecommitdiffstats
path: root/mesonbuild/modules/gnome.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/modules/gnome.py')
-rw-r--r--mesonbuild/modules/gnome.py2165
1 files changed, 2165 insertions, 0 deletions
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
new file mode 100644
index 0000000..38a176d
--- /dev/null
+++ b/mesonbuild/modules/gnome.py
@@ -0,0 +1,2165 @@
+# Copyright 2015-2016 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+'''This module provides helper functions for Gnome/GLib related
+functionality such as gobject-introspection, gresources and gtk-doc'''
+from __future__ import annotations
+
+import copy
+import itertools
+import functools
+import os
+import subprocess
+import textwrap
+import typing as T
+
+from . import ExtensionModule, ModuleInfo
+from . import ModuleReturnValue
+from .. import build
+from .. import interpreter
+from .. import mesonlib
+from .. import mlog
+from ..build import CustomTarget, CustomTargetIndex, Executable, GeneratedList, InvalidArguments
+from ..dependencies import Dependency, PkgConfigDependency, InternalDependency
+from ..interpreter.type_checking import DEPENDS_KW, DEPEND_FILES_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType, SOURCES_KW, in_set_validator
+from ..interpreterbase import noPosargs, noKwargs, FeatureNew, FeatureDeprecated
+from ..interpreterbase import typed_kwargs, KwargInfo, ContainerTypeInfo
+from ..interpreterbase.decorators import typed_pos_args
+from ..mesonlib import (
+ MachineChoice, MesonException, OrderedSet, Popen_safe, join_args,
+)
+from ..programs import OverrideProgram
+from ..scripts.gettext import read_linguas
+
+if T.TYPE_CHECKING:
+ from typing_extensions import Literal, TypedDict
+
+ from . import ModuleState
+ from ..build import BuildTarget
+ from ..compilers import Compiler
+ from ..interpreter import Interpreter
+ from ..interpreterbase import TYPE_var, TYPE_kwargs
+ from ..mesonlib import FileOrString
+ from ..programs import ExternalProgram
+
+ class PostInstall(TypedDict):
+ glib_compile_schemas: bool
+ gio_querymodules: T.List[str]
+ gtk_update_icon_cache: bool
+ update_desktop_database: bool
+ update_mime_database: bool
+
+ class CompileSchemas(TypedDict):
+
+ build_by_default: bool
+ depend_files: T.List[FileOrString]
+
+ class Yelp(TypedDict):
+
+ languages: T.List[str]
+ media: T.List[str]
+ sources: T.List[str]
+ symlink_media: bool
+
+ class CompileResources(TypedDict):
+
+ build_by_default: bool
+ c_name: T.Optional[str]
+ dependencies: T.List[T.Union[mesonlib.File, build.CustomTarget, build.CustomTargetIndex]]
+ export: bool
+ extra_args: T.List[str]
+ gresource_bundle: bool
+ install: bool
+ install_dir: T.Optional[str]
+ install_header: bool
+ source_dir: T.List[str]
+
+ class GenerateGir(TypedDict):
+
+ build_by_default: bool
+ dependencies: T.List[Dependency]
+ export_packages: T.List[str]
+ extra_args: T.List[str]
+ fatal_warnings: bool
+ header: T.List[str]
+ identifier_prefix: T.List[str]
+ include_directories: T.List[T.Union[build.IncludeDirs, str]]
+ includes: T.List[T.Union[str, GirTarget]]
+ install: bool
+ install_dir_gir: T.Optional[str]
+ install_dir_typelib: T.Optional[str]
+ link_with: T.List[T.Union[build.SharedLibrary, build.StaticLibrary]]
+ namespace: str
+ nsversion: str
+ sources: T.List[T.Union[FileOrString, build.GeneratedTypes]]
+ symbol_prefix: T.List[str]
+
+ class GtkDoc(TypedDict):
+
+ src_dir: T.List[T.Union[str, build.IncludeDirs]]
+ main_sgml: str
+ main_xml: str
+ module_version: str
+ namespace: str
+ mode: Literal['xml', 'smgl', 'auto', 'none']
+ html_args: T.List[str]
+ scan_args: T.List[str]
+ scanobjs_args: T.List[str]
+ fixxref_args: T.List[str]
+ mkdb_args: T.List[str]
+ content_files: T.List[T.Union[build.GeneratedTypes, FileOrString]]
+ ignore_headers: T.List[str]
+ install_dir: T.List[str]
+ check: bool
+ install: bool
+ gobject_typesfile: T.List[FileOrString]
+ html_assets: T.List[FileOrString]
+ expand_content_files: T.List[FileOrString]
+ c_args: T.List[str]
+ include_directories: T.List[T.Union[str, build.IncludeDirs]]
+ dependencies: T.List[T.Union[Dependency, build.SharedLibrary, build.StaticLibrary]]
+
+ class GdbusCodegen(TypedDict):
+
+ sources: T.List[FileOrString]
+ extra_args: T.List[str]
+ interface_prefix: T.Optional[str]
+ namespace: T.Optional[str]
+ object_manager: bool
+ build_by_default: bool
+ annotations: T.List[T.List[str]]
+ install_header: bool
+ install_dir: T.Optional[str]
+ docbook: T.Optional[str]
+ autocleanup: Literal['all', 'none', 'objects', 'default']
+
+ class GenMarshal(TypedDict):
+
+ build_always: T.Optional[str]
+ build_always_stale: T.Optional[bool]
+ build_by_default: T.Optional[bool]
+ depend_files: T.List[mesonlib.File]
+ extra_args: T.List[str]
+ install_dir: T.Optional[str]
+ install_header: bool
+ internal: bool
+ nostdinc: bool
+ prefix: T.Optional[str]
+ skip_source: bool
+ sources: T.List[FileOrString]
+ stdinc: bool
+ valist_marshallers: bool
+
+ class GenerateVapi(TypedDict):
+
+ sources: T.List[T.Union[str, GirTarget]]
+ install_dir: T.Optional[str]
+ install: bool
+ vapi_dirs: T.List[str]
+ metadata_dirs: T.List[str]
+ gir_dirs: T.List[str]
+ packages: T.List[T.Union[str, InternalDependency]]
+
+ class _MkEnumsCommon(TypedDict):
+
+ sources: T.List[T.Union[FileOrString, build.GeneratedTypes]]
+ install_header: bool
+ install_dir: T.Optional[str]
+ identifier_prefix: T.Optional[str]
+ symbol_prefix: T.Optional[str]
+
+ class MkEnumsSimple(_MkEnumsCommon):
+
+ header_prefix: str
+ decorator: str
+ function_prefix: str
+ body_prefix: str
+
+ class MkEnums(_MkEnumsCommon):
+
+ c_template: T.Optional[FileOrString]
+ h_template: T.Optional[FileOrString]
+ comments: T.Optional[str]
+ eprod: T.Optional[str]
+ fhead: T.Optional[str]
+ fprod: T.Optional[str]
+ ftail: T.Optional[str]
+ vhead: T.Optional[str]
+ vprod: T.Optional[str]
+ vtail: T.Optional[str]
+ depends: T.List[T.Union[BuildTarget, CustomTarget, CustomTargetIndex]]
+
+
+# Differs from the CustomTarget version in that it straight defaults to True
+_BUILD_BY_DEFAULT: KwargInfo[bool] = KwargInfo(
+ 'build_by_default', bool, default=True,
+)
+
+_EXTRA_ARGS_KW: KwargInfo[T.List[str]] = KwargInfo(
+ 'extra_args',
+ ContainerTypeInfo(list, str),
+ default=[],
+ listify=True,
+)
+
+_MK_ENUMS_COMMON_KWS: T.List[KwargInfo] = [
+ INSTALL_KW.evolve(name='install_header'),
+ INSTALL_DIR_KW,
+ KwargInfo(
+ 'sources',
+ ContainerTypeInfo(list, (str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)),
+ listify=True,
+ required=True,
+ ),
+ KwargInfo('identifier_prefix', (str, NoneType)),
+ KwargInfo('symbol_prefix', (str, NoneType)),
+]
+
+def annotations_validator(annotations: T.List[T.Union[str, T.List[str]]]) -> T.Optional[str]:
+ """Validate gdbus-codegen annotations argument"""
+
+ badlist = 'must be made up of 3 strings for ELEMENT, KEY, and VALUE'
+
+ if not annotations:
+ return None
+ elif all(isinstance(annot, str) for annot in annotations):
+ if len(annotations) == 3:
+ return None
+ else:
+ return badlist
+ elif not all(isinstance(annot, list) for annot in annotations):
+ for c, annot in enumerate(annotations):
+ if not isinstance(annot, list):
+ return f'element {c+1} must be a list'
+ else:
+ for c, annot in enumerate(annotations):
+ if len(annot) != 3 or not all(isinstance(i, str) for i in annot):
+ return f'element {c+1} {badlist}'
+ return None
+
+class GResourceTarget(build.CustomTarget):
+ pass
+
+class GResourceHeaderTarget(build.CustomTarget):
+ pass
+
+class GirTarget(build.CustomTarget):
+ pass
+
+class TypelibTarget(build.CustomTarget):
+ pass
+
+class VapiTarget(build.CustomTarget):
+ pass
+
+# gresource compilation is broken due to the way
+# the resource compiler and Ninja clash about it
+#
+# https://github.com/ninja-build/ninja/issues/1184
+# https://bugzilla.gnome.org/show_bug.cgi?id=774368
+gresource_dep_needed_version = '>= 2.51.1'
+
+class GnomeModule(ExtensionModule):
+
+ INFO = ModuleInfo('gnome')
+
+ def __init__(self, interpreter: 'Interpreter') -> None:
+ super().__init__(interpreter)
+ self.gir_dep: T.Optional[Dependency] = None
+ self.giscanner: T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]] = None
+ self.gicompiler: T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]] = None
+ self.install_glib_compile_schemas = False
+ self.install_gio_querymodules: T.List[str] = []
+ self.install_gtk_update_icon_cache = False
+ self.install_update_desktop_database = False
+ self.install_update_mime_database = False
+ self.devenv: T.Optional[build.EnvironmentVariables] = None
+ self.native_glib_version: T.Optional[str] = None
+ self.methods.update({
+ 'post_install': self.post_install,
+ 'compile_resources': self.compile_resources,
+ 'generate_gir': self.generate_gir,
+ 'compile_schemas': self.compile_schemas,
+ 'yelp': self.yelp,
+ 'gtkdoc': self.gtkdoc,
+ 'gtkdoc_html_dir': self.gtkdoc_html_dir,
+ 'gdbus_codegen': self.gdbus_codegen,
+ 'mkenums': self.mkenums,
+ 'mkenums_simple': self.mkenums_simple,
+ 'genmarshal': self.genmarshal,
+ 'generate_vapi': self.generate_vapi,
+ })
+
+ def _get_native_glib_version(self, state: 'ModuleState') -> str:
+ if self.native_glib_version is None:
+ glib_dep = PkgConfigDependency('glib-2.0', state.environment,
+ {'native': True, 'required': False})
+ if glib_dep.found():
+ self.native_glib_version = glib_dep.get_version()
+ else:
+ mlog.warning('Could not detect glib version, assuming 2.54. '
+ 'You may get build errors if your glib is older.')
+ self.native_glib_version = '2.54'
+ return self.native_glib_version
+
+ @mesonlib.run_once
+ def __print_gresources_warning(self, state: 'ModuleState') -> None:
+ if not mesonlib.version_compare(self._get_native_glib_version(state),
+ gresource_dep_needed_version):
+ mlog.warning('GLib compiled dependencies do not work reliably with \n'
+ 'the current version of GLib. See the following upstream issue:',
+ mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=774368'))
+
+ @staticmethod
+ def _print_gdbus_warning() -> None:
+ mlog.warning('Code generated with gdbus_codegen() requires the root directory be added to\n'
+ ' include_directories of targets with GLib < 2.51.3:',
+ mlog.bold('https://github.com/mesonbuild/meson/issues/1387'),
+ once=True)
+
+ @typed_kwargs(
+ 'gnome.post_install',
+ KwargInfo('glib_compile_schemas', bool, default=False),
+ KwargInfo('gio_querymodules', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('gtk_update_icon_cache', bool, default=False),
+ KwargInfo('update_desktop_database', bool, default=False, since='0.59.0'),
+ KwargInfo('update_mime_database', bool, default=False, since='0.64.0'),
+ )
+ @noPosargs
+ @FeatureNew('gnome.post_install', '0.57.0')
+ def post_install(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'PostInstall') -> ModuleReturnValue:
+ rv: T.List['build.ExecutableSerialisation'] = []
+ datadir_abs = os.path.join(state.environment.get_prefix(), state.environment.get_datadir())
+ if kwargs['glib_compile_schemas'] and not self.install_glib_compile_schemas:
+ self.install_glib_compile_schemas = True
+ prog = state.find_tool('glib-compile-schemas', 'gio-2.0', 'glib_compile_schemas')
+ schemasdir = os.path.join(datadir_abs, 'glib-2.0', 'schemas')
+ script = state.backend.get_executable_serialisation([prog, schemasdir])
+ script.skip_if_destdir = True
+ rv.append(script)
+ for d in kwargs['gio_querymodules']:
+ if d not in self.install_gio_querymodules:
+ self.install_gio_querymodules.append(d)
+ prog = state.find_tool('gio-querymodules', 'gio-2.0', 'gio_querymodules')
+ moduledir = os.path.join(state.environment.get_prefix(), d)
+ script = state.backend.get_executable_serialisation([prog, moduledir])
+ script.skip_if_destdir = True
+ rv.append(script)
+ if kwargs['gtk_update_icon_cache'] and not self.install_gtk_update_icon_cache:
+ self.install_gtk_update_icon_cache = True
+ prog = state.find_program('gtk4-update-icon-cache', required=False)
+ found = isinstance(prog, build.Executable) or prog.found()
+ if not found:
+ prog = state.find_program('gtk-update-icon-cache')
+ icondir = os.path.join(datadir_abs, 'icons', 'hicolor')
+ script = state.backend.get_executable_serialisation([prog, '-q', '-t', '-f', icondir])
+ script.skip_if_destdir = True
+ rv.append(script)
+ if kwargs['update_desktop_database'] and not self.install_update_desktop_database:
+ self.install_update_desktop_database = True
+ prog = state.find_program('update-desktop-database')
+ appdir = os.path.join(datadir_abs, 'applications')
+ script = state.backend.get_executable_serialisation([prog, '-q', appdir])
+ script.skip_if_destdir = True
+ rv.append(script)
+ if kwargs['update_mime_database'] and not self.install_update_mime_database:
+ self.install_update_mime_database = True
+ prog = state.find_program('update-mime-database')
+ appdir = os.path.join(datadir_abs, 'mime')
+ script = state.backend.get_executable_serialisation([prog, appdir])
+ script.skip_if_destdir = True
+ rv.append(script)
+ return ModuleReturnValue(None, rv)
+
+ @typed_pos_args('gnome.compile_resources', str, (str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList))
+ @typed_kwargs(
+ 'gnome.compile_resources',
+ _BUILD_BY_DEFAULT,
+ _EXTRA_ARGS_KW,
+ INSTALL_KW,
+ INSTALL_KW.evolve(name='install_header', since='0.37.0'),
+ INSTALL_DIR_KW,
+ KwargInfo('c_name', (str, NoneType)),
+ KwargInfo('dependencies', ContainerTypeInfo(list, (mesonlib.File, build.CustomTarget, build.CustomTargetIndex)), default=[], listify=True),
+ KwargInfo('export', bool, default=False, since='0.37.0'),
+ KwargInfo('gresource_bundle', bool, default=False, since='0.37.0'),
+ KwargInfo('source_dir', ContainerTypeInfo(list, str), default=[], listify=True),
+ )
+ def compile_resources(self, state: 'ModuleState', args: T.Tuple[str, 'FileOrString'],
+ kwargs: 'CompileResources') -> 'ModuleReturnValue':
+ self.__print_gresources_warning(state)
+ glib_version = self._get_native_glib_version(state)
+
+ glib_compile_resources = state.find_program('glib-compile-resources')
+ cmd: T.List[T.Union[ExternalProgram, str]] = [glib_compile_resources, '@INPUT@']
+
+ source_dirs = kwargs['source_dir']
+ dependencies = kwargs['dependencies']
+
+ target_name, input_file = args
+
+ # Validate dependencies
+ subdirs: T.List[str] = []
+ depends: T.List[T.Union[build.CustomTarget, build.CustomTargetIndex]] = []
+ for dep in dependencies:
+ if isinstance(dep, mesonlib.File):
+ subdirs.append(dep.subdir)
+ else:
+ depends.append(dep)
+ subdirs.append(dep.get_subdir())
+ if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
+ m = 'The "dependencies" argument of gnome.compile_resources() can not\n' \
+ 'be used with the current version of glib-compile-resources due to\n' \
+ '<https://bugzilla.gnome.org/show_bug.cgi?id=774368>'
+ raise MesonException(m)
+
+ if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
+ # Resource xml files generated at build-time cannot be used with
+ # gnome.compile_resources() because we need to scan the xml for
+ # dependencies. Use configure_file() instead to generate it at
+ # configure-time
+ if isinstance(input_file, mesonlib.File):
+ # glib-compile-resources will be run inside the source dir,
+ # so we need either 'src_to_build' or the absolute path.
+ # Absolute path is the easiest choice.
+ if input_file.is_built:
+ ifile = os.path.join(state.environment.get_build_dir(), input_file.subdir, input_file.fname)
+ else:
+ ifile = os.path.join(input_file.subdir, input_file.fname)
+
+ elif isinstance(input_file, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)):
+ raise MesonException('Resource xml files generated at build-time cannot be used with '
+ 'gnome.compile_resources() in the current version of glib-compile-resources '
+ 'because we need to scan the xml for dependencies due to '
+ '<https://bugzilla.gnome.org/show_bug.cgi?id=774368>\nUse '
+ 'configure_file() instead to generate it at configure-time.')
+ else:
+ ifile = os.path.join(state.subdir, input_file)
+
+ depend_files, depends, subdirs = self._get_gresource_dependencies(
+ state, ifile, source_dirs, dependencies)
+
+ # Make source dirs relative to build dir now
+ source_dirs = [os.path.join(state.build_to_src, state.subdir, d) for d in source_dirs]
+ # Ensure build directories of generated deps are included
+ source_dirs += subdirs
+ # 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):
+ cmd += ['--sourcedir', source_dir]
+
+ if kwargs['c_name']:
+ cmd += ['--c-name', kwargs['c_name']]
+ if not kwargs['export']:
+ cmd += ['--internal']
+
+ cmd += ['--generate', '--target', '@OUTPUT@']
+ cmd += kwargs['extra_args']
+
+ gresource = kwargs['gresource_bundle']
+ if gresource:
+ output = f'{target_name}.gresource'
+ name = f'{target_name}_gresource'
+ else:
+ if 'c' in state.environment.coredata.compilers.host:
+ output = f'{target_name}.c'
+ name = f'{target_name}_c'
+ elif 'cpp' in state.environment.coredata.compilers.host:
+ output = f'{target_name}.cpp'
+ name = f'{target_name}_cpp'
+ else:
+ raise MesonException('Compiling GResources into code is only supported in C and C++ projects')
+
+ if kwargs['install'] and not gresource:
+ raise MesonException('The install kwarg only applies to gresource bundles, see install_header')
+
+ install_header = kwargs['install_header']
+ if install_header and gresource:
+ raise MesonException('The install_header kwarg does not apply to gresource bundles')
+ if install_header and not kwargs['export']:
+ raise MesonException('GResource header is installed yet export is not enabled')
+
+ depfile: T.Optional[str] = None
+ target_cmd: T.List[T.Union[ExternalProgram, str]]
+ if not mesonlib.version_compare(glib_version, gresource_dep_needed_version):
+ # This will eventually go out of sync if dependencies are added
+ target_cmd = cmd
+ else:
+ depfile = f'{output}.d'
+ depend_files = []
+ target_cmd = copy.copy(cmd) + ['--dependency-file', '@DEPFILE@']
+ target_c = GResourceTarget(
+ name,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ target_cmd,
+ [input_file],
+ [output],
+ build_by_default=kwargs['build_by_default'],
+ depfile=depfile,
+ depend_files=depend_files,
+ extra_depends=depends,
+ install=kwargs['install'],
+ install_dir=[kwargs['install_dir']] if kwargs['install_dir'] else [],
+ install_tag=['runtime'],
+ )
+
+ if gresource: # Only one target for .gresource files
+ return ModuleReturnValue(target_c, [target_c])
+
+ install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
+ assert isinstance(install_dir, str), 'for mypy'
+ target_h = GResourceHeaderTarget(
+ f'{target_name}_h',
+ state.subdir,
+ state.subproject,
+ state.environment,
+ cmd,
+ [input_file],
+ [f'{target_name}.h'],
+ build_by_default=kwargs['build_by_default'],
+ extra_depends=depends,
+ install=install_header,
+ install_dir=[install_dir],
+ install_tag=['devel'],
+ )
+ rv = [target_c, target_h]
+ return ModuleReturnValue(rv, rv)
+
+ @staticmethod
+ def _get_gresource_dependencies(
+ state: 'ModuleState', input_file: str, source_dirs: T.List[str],
+ dependencies: T.Sequence[T.Union[mesonlib.File, build.CustomTarget, build.CustomTargetIndex]]
+ ) -> T.Tuple[T.List[mesonlib.FileOrString], T.List[T.Union[build.CustomTarget, build.CustomTargetIndex]], T.List[str]]:
+
+ cmd = ['glib-compile-resources',
+ input_file,
+ '--generate-dependencies']
+
+ # Prefer generated files over source files
+ cmd += ['--sourcedir', state.subdir] # Current build dir
+ for source_dir in source_dirs:
+ cmd += ['--sourcedir', os.path.join(state.subdir, source_dir)]
+
+ try:
+ pc, stdout, stderr = Popen_safe(cmd, cwd=state.environment.get_source_dir())
+ except (FileNotFoundError, PermissionError):
+ raise MesonException('Could not execute glib-compile-resources.')
+ if pc.returncode != 0:
+ m = f'glib-compile-resources failed to get dependencies for {cmd[1]}:\n{stderr}'
+ mlog.warning(m)
+ raise subprocess.CalledProcessError(pc.returncode, cmd)
+
+ raw_dep_files: T.List[str] = stdout.split('\n')[:-1]
+
+ depends: T.List[T.Union[build.CustomTarget, build.CustomTargetIndex]] = []
+ subdirs: T.List[str] = []
+ dep_files: T.List[mesonlib.FileOrString] = []
+ for resfile in raw_dep_files.copy():
+ resbasename = os.path.basename(resfile)
+ for dep in dependencies:
+ if isinstance(dep, mesonlib.File):
+ if dep.fname != resbasename:
+ continue
+ raw_dep_files.remove(resfile)
+ dep_files.append(dep)
+ subdirs.append(dep.subdir)
+ break
+ elif isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)):
+ fname = None
+ outputs = {(o, os.path.basename(o)) for o in dep.get_outputs()}
+ for o, baseo in outputs:
+ if baseo == resbasename:
+ fname = o
+ break
+ if fname is not None:
+ raw_dep_files.remove(resfile)
+ depends.append(dep)
+ subdirs.append(dep.get_subdir())
+ break
+ else:
+ # In generate-dependencies mode, glib-compile-resources doesn't raise
+ # an error for missing resources but instead prints whatever filename
+ # was listed in the input file. That's good because it means we can
+ # handle resource files that get generated as part of the build, as
+ # follows.
+ #
+ # If there are multiple generated resource files with the same basename
+ # then this code will get confused.
+ try:
+ f = mesonlib.File.from_source_file(state.environment.get_source_dir(),
+ ".", resfile)
+ except MesonException:
+ raise MesonException(
+ f'Resource "{resfile}" listed in "{input_file}" was not found. '
+ 'If this is a generated file, pass the target that generates '
+ 'it to gnome.compile_resources() using the "dependencies" '
+ 'keyword argument.')
+ raw_dep_files.remove(resfile)
+ dep_files.append(f)
+ dep_files.extend(raw_dep_files)
+ return dep_files, depends, subdirs
+
+ def _get_link_args(self, state: 'ModuleState',
+ lib: T.Union[build.SharedLibrary, build.StaticLibrary],
+ depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]],
+ include_rpath: bool = False,
+ use_gir_args: bool = False
+ ) -> T.Tuple[T.List[str], T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
+ link_command: T.List[str] = []
+ new_depends = list(depends)
+ # Construct link args
+ if isinstance(lib, build.SharedLibrary):
+ libdir = os.path.join(state.environment.get_build_dir(), state.backend.get_target_dir(lib))
+ link_command.append('-L' + libdir)
+ if include_rpath:
+ link_command.append('-Wl,-rpath,' + libdir)
+ new_depends.append(lib)
+ # 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(lib):
+ d = os.path.join(state.environment.get_build_dir(), d)
+ link_command.append('-L' + d)
+ if include_rpath:
+ link_command.append('-Wl,-rpath,' + d)
+ if use_gir_args and self._gir_has_option('--extra-library'):
+ link_command.append('--extra-library=' + lib.name)
+ else:
+ link_command.append('-l' + lib.name)
+ return link_command, new_depends
+
+ def _get_dependencies_flags_raw(
+ self, deps: T.Sequence[T.Union['Dependency', build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]],
+ state: 'ModuleState',
+ depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]],
+ include_rpath: bool,
+ use_gir_args: bool,
+ ) -> T.Tuple[OrderedSet[str], OrderedSet[T.Union[str, T.Tuple[str, str]]], OrderedSet[T.Union[str, T.Tuple[str, str]]], OrderedSet[str],
+ T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
+ cflags: OrderedSet[str] = OrderedSet()
+ # External linker flags that can't be de-duped reliably because they
+ # require two args in order, such as -framework AVFoundation will be stored as a tuple.
+ internal_ldflags: OrderedSet[T.Union[str, T.Tuple[str, str]]] = OrderedSet()
+ external_ldflags: OrderedSet[T.Union[str, T.Tuple[str, str]]] = OrderedSet()
+ gi_includes: OrderedSet[str] = OrderedSet()
+ deps = mesonlib.listify(deps)
+ depends = list(depends)
+
+ for dep in deps:
+ if isinstance(dep, Dependency):
+ girdir = dep.get_variable(pkgconfig='girdir', internal='girdir', default_value='')
+ if girdir:
+ assert isinstance(girdir, str), 'for mypy'
+ gi_includes.update([girdir])
+ if isinstance(dep, InternalDependency):
+ cflags.update(dep.get_compile_args())
+ cflags.update(state.get_include_args(dep.include_directories))
+ for lib in dep.libraries:
+ if isinstance(lib, build.SharedLibrary):
+ _ld, depends = self._get_link_args(state, lib, depends, include_rpath)
+ internal_ldflags.update(_ld)
+ libdepflags = self._get_dependencies_flags_raw(lib.get_external_deps(), state, depends, include_rpath,
+ use_gir_args)
+ cflags.update(libdepflags[0])
+ internal_ldflags.update(libdepflags[1])
+ external_ldflags.update(libdepflags[2])
+ gi_includes.update(libdepflags[3])
+ depends = libdepflags[4]
+ extdepflags = self._get_dependencies_flags_raw(dep.ext_deps, state, depends, include_rpath,
+ use_gir_args)
+ cflags.update(extdepflags[0])
+ internal_ldflags.update(extdepflags[1])
+ external_ldflags.update(extdepflags[2])
+ gi_includes.update(extdepflags[3])
+ depends = extdepflags[4]
+ for source in dep.sources:
+ if isinstance(source, GirTarget):
+ gi_includes.update([os.path.join(state.environment.get_build_dir(),
+ source.get_subdir())])
+ # This should be any dependency other than an internal one.
+ elif isinstance(dep, Dependency):
+ cflags.update(dep.get_compile_args())
+ ldflags = iter(dep.get_link_args(raw=True))
+ for flag in ldflags:
+ if (os.path.isabs(flag) and
+ # For PkgConfigDependency only:
+ getattr(dep, 'is_libtool', False)):
+ lib_dir = os.path.dirname(flag)
+ external_ldflags.update([f'-L{lib_dir}'])
+ if include_rpath:
+ external_ldflags.update([f'-Wl,-rpath {lib_dir}'])
+ libname = os.path.basename(flag)
+ if libname.startswith("lib"):
+ libname = libname[3:]
+ libname = libname.split(".so")[0]
+ flag = f"-l{libname}"
+ # FIXME: Hack to avoid passing some compiler options in
+ if flag.startswith("-W"):
+ continue
+ # If it's a framework arg, slurp the framework name too
+ # to preserve the order of arguments
+ if flag == '-framework':
+ external_ldflags.update([(flag, next(ldflags))])
+ else:
+ external_ldflags.update([flag])
+ elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
+ cflags.update(state.get_include_args(dep.get_include_dirs()))
+ depends.append(dep)
+ else:
+ mlog.log(f'dependency {dep!r} not handled to build gir files')
+ continue
+
+ if use_gir_args and self._gir_has_option('--extra-library'):
+ def fix_ldflags(ldflags: T.Iterable[T.Union[str, T.Tuple[str, str]]]) -> OrderedSet[T.Union[str, T.Tuple[str, str]]]:
+ fixed_ldflags: OrderedSet[T.Union[str, T.Tuple[str, str]]] = OrderedSet()
+ for ldflag in ldflags:
+ if isinstance(ldflag, str) and ldflag.startswith("-l"):
+ ldflag = ldflag.replace('-l', '--extra-library=', 1)
+ fixed_ldflags.add(ldflag)
+ return fixed_ldflags
+ internal_ldflags = fix_ldflags(internal_ldflags)
+ external_ldflags = fix_ldflags(external_ldflags)
+ return cflags, internal_ldflags, external_ldflags, gi_includes, depends
+
+ def _get_dependencies_flags(
+ self, deps: T.Sequence[T.Union['Dependency', build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]],
+ state: 'ModuleState',
+ depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]],
+ include_rpath: bool = False,
+ use_gir_args: bool = False,
+ ) -> T.Tuple[OrderedSet[str], T.List[str], T.List[str], OrderedSet[str],
+ T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
+
+ cflags, internal_ldflags_raw, external_ldflags_raw, gi_includes, depends = self._get_dependencies_flags_raw(deps, state, depends, include_rpath, use_gir_args)
+ internal_ldflags: T.List[str] = []
+ external_ldflags: T.List[str] = []
+
+ # Extract non-deduplicable argument groups out of the tuples.
+ for ldflag in internal_ldflags_raw:
+ if isinstance(ldflag, str):
+ internal_ldflags.append(ldflag)
+ else:
+ internal_ldflags.extend(ldflag)
+ for ldflag in external_ldflags_raw:
+ if isinstance(ldflag, str):
+ external_ldflags.append(ldflag)
+ else:
+ external_ldflags.extend(ldflag)
+
+ return cflags, internal_ldflags, external_ldflags, gi_includes, depends
+
+ def _unwrap_gir_target(self, girtarget: T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary], state: 'ModuleState'
+ ) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary]:
+ if not isinstance(girtarget, (build.Executable, build.SharedLibrary,
+ build.StaticLibrary)):
+ raise MesonException(f'Gir target must be an executable or library but is "{girtarget}" of type {type(girtarget).__name__}')
+
+ STATIC_BUILD_REQUIRED_VERSION = ">=1.58.1"
+ if isinstance(girtarget, (build.StaticLibrary)) and \
+ not mesonlib.version_compare(
+ self._get_gir_dep(state)[0].get_version(),
+ STATIC_BUILD_REQUIRED_VERSION):
+ raise MesonException('Static libraries can only be introspected with GObject-Introspection ' + STATIC_BUILD_REQUIRED_VERSION)
+
+ return girtarget
+
+ def _devenv_prepend(self, varname: str, value: str) -> None:
+ if self.devenv is None:
+ self.devenv = build.EnvironmentVariables()
+ self.devenv.prepend(varname, [value])
+
+ def get_devenv(self) -> T.Optional[build.EnvironmentVariables]:
+ return self.devenv
+
+ def _get_gir_dep(self, state: 'ModuleState') -> T.Tuple[Dependency, T.Union[build.Executable, 'ExternalProgram', 'OverrideProgram'],
+ T.Union[build.Executable, 'ExternalProgram', 'OverrideProgram']]:
+ if not self.gir_dep:
+ self.gir_dep = state.dependency('gobject-introspection-1.0')
+ self.giscanner = state.find_tool('g-ir-scanner', 'gobject-introspection-1.0', 'g_ir_scanner')
+ self.gicompiler = state.find_tool('g-ir-compiler', 'gobject-introspection-1.0', 'g_ir_compiler')
+ return self.gir_dep, self.giscanner, self.gicompiler
+
+ @functools.lru_cache(maxsize=None)
+ def _gir_has_option(self, option: str) -> bool:
+ exe = self.giscanner
+ if isinstance(exe, OverrideProgram):
+ # Handle overridden g-ir-scanner
+ assert option in {'--extra-library', '--sources-top-dirs'}
+ return True
+ p, o, _ = Popen_safe(exe.get_command() + ['--help'], stderr=subprocess.STDOUT)
+ return p.returncode == 0 and option in o
+
+ # May mutate depends and gir_inc_dirs
+ @staticmethod
+ def _scan_include(state: 'ModuleState', includes: T.List[T.Union[str, GirTarget]]
+ ) -> T.Tuple[T.List[str], T.List[str], T.List[GirTarget]]:
+ ret: T.List[str] = []
+ gir_inc_dirs: T.List[str] = []
+ depends: T.List[GirTarget] = []
+
+ for inc in includes:
+ if isinstance(inc, str):
+ ret += [f'--include={inc}']
+ elif isinstance(inc, GirTarget):
+ gir_inc_dirs .append(os.path.join(state.environment.get_build_dir(), inc.get_subdir()))
+ ret.append(f"--include-uninstalled={os.path.join(inc.get_subdir(), inc.get_basename())}")
+ depends.append(inc)
+
+ return ret, gir_inc_dirs, depends
+
+ @staticmethod
+ def _scan_langs(state: 'ModuleState', langs: T.Iterable[str]) -> T.List[str]:
+ ret: T.List[str] = []
+
+ for lang in langs:
+ link_args = state.environment.coredata.get_external_link_args(MachineChoice.HOST, lang)
+ for link_arg in link_args:
+ if link_arg.startswith('-L'):
+ ret.append(link_arg)
+
+ return ret
+
+ @staticmethod
+ def _scan_gir_targets(state: 'ModuleState', girtargets: T.Sequence[build.BuildTarget]) -> T.List[T.Union[str, build.Executable]]:
+ ret: T.List[T.Union[str, build.Executable]] = []
+
+ for girtarget in girtargets:
+ if isinstance(girtarget, build.Executable):
+ ret += ['--program', girtarget]
+ else:
+ # Because of https://gitlab.gnome.org/GNOME/gobject-introspection/merge_requests/72
+ # we can't use the full path until this is merged.
+ libpath = os.path.join(girtarget.get_subdir(), girtarget.get_filename())
+ # Must use absolute paths here because g-ir-scanner will not
+ # add them to the runtime path list if they're relative. This
+ # means we cannot use @BUILD_ROOT@
+ build_root = state.environment.get_build_dir()
+ if isinstance(girtarget, build.SharedLibrary):
+ # 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{}/{}".format(build_root, os.path.dirname(libpath))]
+ libname = girtarget.get_basename()
+ else:
+ libname = os.path.join(f"{build_root}/{libpath}")
+ ret += ['--library', libname]
+ # 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)
+
+ return ret
+
+ @staticmethod
+ def _get_girtargets_langs_compilers(girtargets: T.Sequence[build.BuildTarget]) -> T.List[T.Tuple[str, 'Compiler']]:
+ ret: T.List[T.Tuple[str, 'Compiler']] = []
+ 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
+
+ @staticmethod
+ def _get_gir_targets_deps(girtargets: T.Sequence[build.BuildTarget]
+ ) -> T.List[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex, Dependency]]:
+ ret: T.List[T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex, Dependency]] = []
+ for girtarget in girtargets:
+ ret += girtarget.get_all_link_deps()
+ ret += girtarget.get_external_deps()
+ return ret
+
+ @staticmethod
+ def _get_gir_targets_inc_dirs(girtargets: T.Sequence[build.BuildTarget]) -> OrderedSet[build.IncludeDirs]:
+ ret: OrderedSet = OrderedSet()
+ for girtarget in girtargets:
+ ret.update(girtarget.get_include_dirs())
+ return ret
+
+ @staticmethod
+ def _get_langs_compilers_flags(state: 'ModuleState', langs_compilers: T.List[T.Tuple[str, 'Compiler']]
+ ) -> T.Tuple[T.List[str], T.List[str], T.List[str]]:
+ cflags: T.List[str] = []
+ internal_ldflags: T.List[str] = []
+ external_ldflags: T.List[str] = []
+
+ for lang, compiler in langs_compilers:
+ if state.global_args.get(lang):
+ cflags += state.global_args[lang]
+ if state.project_args.get(lang):
+ cflags += state.project_args[lang]
+ if mesonlib.OptionKey('b_sanitize') in compiler.base_options:
+ sanitize = state.environment.coredata.options[mesonlib.OptionKey('b_sanitize')].value
+ cflags += compiler.sanitizer_compile_args(sanitize)
+ sanitize = sanitize.split(',')
+ # These must be first in ldflags
+ if 'address' in sanitize:
+ internal_ldflags += ['-lasan']
+ if 'thread' in sanitize:
+ internal_ldflags += ['-ltsan']
+ if 'undefined' in sanitize:
+ internal_ldflags += ['-lubsan']
+ # FIXME: Linking directly to lib*san is not recommended but g-ir-scanner
+ # does not understand -f LDFLAGS. https://bugzilla.gnome.org/show_bug.cgi?id=783892
+ # ldflags += compiler.sanitizer_link_args(sanitize)
+
+ return cflags, internal_ldflags, external_ldflags
+
+ @staticmethod
+ def _make_gir_filelist(state: 'ModuleState', srcdir: str, ns: str,
+ nsversion: str, girtargets: T.Sequence[build.BuildTarget],
+ libsources: T.Sequence[T.Union[
+ str, mesonlib.File, build.GeneratedList,
+ build.CustomTarget, build.CustomTargetIndex]]
+ ) -> str:
+ 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, f'{ns}_{nsversion}_gir_filelist')
+
+ with open(gir_filelist_filename, 'w', encoding='utf-8') as gir_filelist:
+ for s in libsources:
+ if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)):
+ for custom_output in s.get_outputs():
+ gir_filelist.write(os.path.join(state.environment.get_build_dir(),
+ state.backend.get_target_dir(s),
+ custom_output) + '\n')
+ elif isinstance(s, mesonlib.File):
+ gir_filelist.write(s.rel_to_builddir(state.build_to_src) + '\n')
+ elif isinstance(s, build.GeneratedList):
+ for gen_src in s.get_outputs():
+ gir_filelist.write(os.path.join(srcdir, gen_src) + '\n')
+ else:
+ gir_filelist.write(os.path.join(srcdir, s) + '\n')
+
+ return gir_filelist_filename
+
+ @staticmethod
+ def _make_gir_target(
+ state: 'ModuleState',
+ girfile: str,
+ scan_command: T.Sequence[T.Union['FileOrString', Executable, ExternalProgram, OverrideProgram]],
+ generated_files: T.Sequence[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]],
+ depends: T.Sequence[T.Union['FileOrString', build.BuildTarget, 'build.GeneratedTypes', build.StructuredSources]],
+ kwargs: T.Dict[str, T.Any]) -> GirTarget:
+ install = kwargs['install_gir']
+ if install is None:
+ install = kwargs['install']
+
+ install_dir = kwargs['install_dir_gir']
+ if install_dir is None:
+ install_dir = os.path.join(state.environment.get_datadir(), 'gir-1.0')
+ elif install_dir is False:
+ install = False
+
+ # g-ir-scanner uses pkg-config to find libraries such as glib. They could
+ # be built as subproject in which case we need to trick it to use
+ # -uninstalled.pc files Meson generated. It also must respect pkgconfig
+ # settings user could have set in machine file, like PKG_CONFIG_LIBDIR,
+ # SYSROOT, etc.
+ run_env = PkgConfigDependency.get_env(state.environment, MachineChoice.HOST, uninstalled=True)
+
+ return GirTarget(
+ girfile,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ scan_command,
+ generated_files,
+ [girfile],
+ build_by_default=kwargs['build_by_default'],
+ extra_depends=depends,
+ install=install,
+ install_dir=[install_dir],
+ install_tag=['devel'],
+ env=run_env,
+ )
+
+ @staticmethod
+ def _make_typelib_target(state: 'ModuleState', typelib_output: str,
+ typelib_cmd: T.Sequence[T.Union[str, build.Executable, ExternalProgram, build.CustomTarget]],
+ generated_files: T.Sequence[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]],
+ kwargs: T.Dict[str, T.Any]) -> TypelibTarget:
+ install = kwargs['install_typelib']
+ if install is None:
+ install = kwargs['install']
+
+ install_dir = kwargs['install_dir_typelib']
+ if install_dir is None:
+ install_dir = os.path.join(state.environment.get_libdir(), 'girepository-1.0')
+ elif install_dir is False:
+ install = False
+
+ return TypelibTarget(
+ typelib_output,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ typelib_cmd,
+ generated_files,
+ [typelib_output],
+ install=install,
+ install_dir=[install_dir],
+ install_tag=['typelib'],
+ build_by_default=kwargs['build_by_default'],
+ )
+
+ @staticmethod
+ def _gather_typelib_includes_and_update_depends(
+ state: 'ModuleState',
+ deps: T.Sequence[T.Union[Dependency, build.BuildTarget, build.CustomTarget, build.CustomTargetIndex]],
+ depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]
+ ) -> T.Tuple[T.List[str], T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
+ # Need to recursively add deps on GirTarget sources from our
+ # dependencies and also find the include directories needed for the
+ # typelib generation custom target below.
+ typelib_includes: T.List[str] = []
+ new_depends = list(depends)
+ for dep in deps:
+ # Add a dependency on each GirTarget listed in dependencies and add
+ # the directory where it will be generated to the typelib includes
+ if isinstance(dep, InternalDependency):
+ for source in dep.sources:
+ if isinstance(source, GirTarget) and source not in depends:
+ new_depends.append(source)
+ subdir = os.path.join(state.environment.get_build_dir(),
+ source.get_subdir())
+ if subdir not in typelib_includes:
+ typelib_includes.append(subdir)
+ # Do the same, but for dependencies of dependencies. These are
+ # stored in the list of generated sources for each link dep (from
+ # girtarget.get_all_link_deps() above).
+ # FIXME: Store this in the original form from declare_dependency()
+ # so it can be used here directly.
+ elif isinstance(dep, build.SharedLibrary):
+ for g_source in dep.generated:
+ if isinstance(g_source, GirTarget):
+ subdir = os.path.join(state.environment.get_build_dir(),
+ g_source.get_subdir())
+ if subdir not in typelib_includes:
+ typelib_includes.append(subdir)
+ if isinstance(dep, Dependency):
+ girdir = dep.get_variable(pkgconfig='girdir', internal='girdir', default_value='')
+ assert isinstance(girdir, str), 'for mypy'
+ if girdir and girdir not in typelib_includes:
+ typelib_includes.append(girdir)
+ return typelib_includes, new_depends
+
+ @staticmethod
+ def _get_external_args_for_langs(state: 'ModuleState', langs: T.List[str]) -> T.List[str]:
+ ret: T.List[str] = []
+ for lang in langs:
+ ret += mesonlib.listify(state.environment.coredata.get_external_args(MachineChoice.HOST, lang))
+ return ret
+
+ @staticmethod
+ def _get_scanner_cflags(cflags: T.Iterable[str]) -> T.Iterable[str]:
+ 'g-ir-scanner only accepts -I/-D/-U; must ignore all other flags'
+ for f in cflags:
+ # _FORTIFY_SOURCE depends on / works together with -O, on the other hand this
+ # just invokes the preprocessor anyway
+ if f.startswith(('-D', '-U', '-I')) and not f.startswith('-D_FORTIFY_SOURCE'):
+ yield f
+
+ @staticmethod
+ def _get_scanner_ldflags(ldflags: T.Iterable[str]) -> T.Iterable[str]:
+ 'g-ir-scanner only accepts -L/-l; must ignore -F and other linker flags'
+ for f in ldflags:
+ if f.startswith(('-L', '-l', '--extra-library')):
+ yield f
+
+ @typed_pos_args('gnome.generate_gir', varargs=(build.Executable, build.SharedLibrary, build.StaticLibrary), min_varargs=1)
+ @typed_kwargs(
+ 'gnome.generate_gir',
+ INSTALL_KW,
+ _BUILD_BY_DEFAULT.evolve(since='0.40.0'),
+ _EXTRA_ARGS_KW,
+ KwargInfo('dependencies', ContainerTypeInfo(list, Dependency), default=[], listify=True),
+ KwargInfo('export_packages', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('fatal_warnings', bool, default=False, since='0.55.0'),
+ KwargInfo('header', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('identifier_prefix', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('include_directories', ContainerTypeInfo(list, (str, build.IncludeDirs)), default=[], listify=True),
+ KwargInfo('includes', ContainerTypeInfo(list, (str, GirTarget)), default=[], listify=True),
+ KwargInfo('install_gir', (bool, NoneType), since='0.61.0'),
+ KwargInfo('install_dir_gir', (str, bool, NoneType),
+ deprecated_values={False: ('0.61.0', 'Use install_gir to disable installation')},
+ validator=lambda x: 'as boolean can only be false' if x is True else None),
+ KwargInfo('install_typelib', (bool, NoneType), since='0.61.0'),
+ KwargInfo('install_dir_typelib', (str, bool, NoneType),
+ deprecated_values={False: ('0.61.0', 'Use install_typelib to disable installation')},
+ validator=lambda x: 'as boolean can only be false' if x is True else None),
+ KwargInfo('link_with', ContainerTypeInfo(list, (build.SharedLibrary, build.StaticLibrary)), default=[], listify=True),
+ KwargInfo('namespace', str, required=True),
+ KwargInfo('nsversion', str, required=True),
+ KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File, build.GeneratedList, build.CustomTarget, build.CustomTargetIndex)), default=[], listify=True),
+ KwargInfo('symbol_prefix', ContainerTypeInfo(list, str), default=[], listify=True),
+ )
+ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[build.Executable, build.SharedLibrary, build.StaticLibrary]]],
+ kwargs: 'GenerateGir') -> ModuleReturnValue:
+ girtargets = [self._unwrap_gir_target(arg, state) for arg in args[0]]
+ 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')
+
+ gir_dep, giscanner, gicompiler = self._get_gir_dep(state)
+
+ ns = kwargs['namespace']
+ nsversion = kwargs['nsversion']
+ libsources = kwargs['sources']
+
+ girfile = f'{ns}-{nsversion}.gir'
+ srcdir = os.path.join(state.environment.get_source_dir(), state.subdir)
+ builddir = os.path.join(state.environment.get_build_dir(), state.subdir)
+
+ depends: T.List[T.Union['FileOrString', 'build.GeneratedTypes', build.BuildTarget, build.StructuredSources]] = []
+ depends.extend(gir_dep.sources)
+ depends.extend(girtargets)
+
+ 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 += kwargs['dependencies']
+ deps += [gir_dep]
+ typelib_includes, depends = 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
+ # are not used here.
+ dep_cflags, dep_internal_ldflags, dep_external_ldflags, gi_includes, depends = \
+ self._get_dependencies_flags(deps, state, depends, use_gir_args=True)
+ scan_cflags = []
+ scan_cflags += list(self._get_scanner_cflags(cflags))
+ scan_cflags += list(self._get_scanner_cflags(dep_cflags))
+ scan_cflags += list(self._get_scanner_cflags(self._get_external_args_for_langs(state, [lc[0] for lc in langs_compilers])))
+ scan_internal_ldflags = []
+ scan_internal_ldflags += list(self._get_scanner_ldflags(internal_ldflags))
+ scan_internal_ldflags += list(self._get_scanner_ldflags(dep_internal_ldflags))
+ scan_external_ldflags = []
+ scan_external_ldflags += list(self._get_scanner_ldflags(external_ldflags))
+ scan_external_ldflags += list(self._get_scanner_ldflags(dep_external_ldflags))
+ girtargets_inc_dirs = self._get_gir_targets_inc_dirs(girtargets)
+ inc_dirs = kwargs['include_directories']
+
+ gir_inc_dirs: T.List[str] = []
+
+ scan_command: T.List[T.Union[str, build.Executable, 'ExternalProgram', 'OverrideProgram']] = [giscanner]
+ scan_command += ['--quiet']
+ scan_command += ['--no-libtool']
+ scan_command += ['--namespace=' + ns, '--nsversion=' + nsversion]
+ scan_command += ['--warn-all']
+ scan_command += ['--output', '@OUTPUT@']
+ scan_command += [f'--c-include={h}' for h in kwargs['header']]
+ scan_command += kwargs['extra_args']
+ scan_command += ['-I' + srcdir, '-I' + builddir]
+ scan_command += state.get_include_args(girtargets_inc_dirs)
+ scan_command += ['--filelist=' + self._make_gir_filelist(state, srcdir, ns, nsversion, girtargets, libsources)]
+ for l in kwargs['link_with']:
+ _cflags, depends = self._get_link_args(state, l, depends, use_gir_args=True)
+ scan_command.extend(_cflags)
+ _cmd, _ginc, _deps = self._scan_include(state, kwargs['includes'])
+ scan_command.extend(_cmd)
+ gir_inc_dirs.extend(_ginc)
+ depends.extend(_deps)
+
+ scan_command += [f'--symbol-prefix={p}' for p in kwargs['symbol_prefix']]
+ scan_command += [f'--identifier-prefix={p}' for p in kwargs['identifier_prefix']]
+ scan_command += [f'--pkg-export={p}' for p in kwargs['export_packages']]
+ scan_command += ['--cflags-begin']
+ scan_command += scan_cflags
+ scan_command += ['--cflags-end']
+ scan_command += state.get_include_args(inc_dirs)
+ scan_command += state.get_include_args(itertools.chain(gi_includes, gir_inc_dirs, inc_dirs), prefix='--add-include-path=')
+ scan_command += list(scan_internal_ldflags)
+ scan_command += self._scan_gir_targets(state, girtargets)
+ scan_command += self._scan_langs(state, [lc[0] for lc in langs_compilers])
+ scan_command += list(scan_external_ldflags)
+
+ if self._gir_has_option('--sources-top-dirs'):
+ scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_source_dir(), state.root_subdir)]
+ scan_command += ['--sources-top-dirs', os.path.join(state.environment.get_build_dir(), state.root_subdir)]
+
+ if '--warn-error' in scan_command:
+ FeatureDeprecated.single_use('gnome.generate_gir argument --warn-error', '0.55.0',
+ state.subproject, 'Use "fatal_warnings" keyword argument', state.current_node)
+ if kwargs['fatal_warnings']:
+ scan_command.append('--warn-error')
+
+ generated_files = [f for f in libsources if isinstance(f, (GeneratedList, CustomTarget, CustomTargetIndex))]
+
+ scan_target = self._make_gir_target(
+ state, girfile, scan_command, generated_files, depends,
+ # We have to cast here because mypy can't figure this out
+ T.cast('T.Dict[str, T.Any]', kwargs))
+
+ typelib_output = f'{ns}-{nsversion}.typelib'
+ typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
+ typelib_cmd += state.get_include_args(gir_inc_dirs, prefix='--includedir=')
+
+ for incdir in typelib_includes:
+ typelib_cmd += ["--includedir=" + incdir]
+
+ typelib_target = self._make_typelib_target(state, typelib_output, typelib_cmd, generated_files, T.cast('T.Dict[str, T.Any]', kwargs))
+
+ self._devenv_prepend('GI_TYPELIB_PATH', os.path.join(state.environment.get_build_dir(), state.subdir))
+
+ rv = [scan_target, typelib_target]
+
+ return ModuleReturnValue(rv, rv)
+
+ @noPosargs
+ @typed_kwargs('gnome.compile_schemas', _BUILD_BY_DEFAULT.evolve(since='0.40.0'), DEPEND_FILES_KW)
+ def compile_schemas(self, state: 'ModuleState', args: T.List['TYPE_var'], kwargs: 'CompileSchemas') -> ModuleReturnValue:
+ srcdir = os.path.join(state.build_to_src, state.subdir)
+ outdir = state.subdir
+
+ cmd: T.List[T.Union[ExternalProgram, str]] = [state.find_program('glib-compile-schemas'), '--targetdir', outdir, srcdir]
+ if state.subdir == '':
+ targetname = 'gsettings-compile'
+ else:
+ targetname = 'gsettings-compile-' + state.subdir.replace('/', '_')
+ target_g = build.CustomTarget(
+ targetname,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ cmd,
+ [],
+ ['gschemas.compiled'],
+ build_by_default=kwargs['build_by_default'],
+ depend_files=kwargs['depend_files'],
+ )
+ self._devenv_prepend('GSETTINGS_SCHEMA_DIR', os.path.join(state.environment.get_build_dir(), state.subdir))
+ return ModuleReturnValue(target_g, [target_g])
+
+ @typed_pos_args('gnome.yelp', str, varargs=str)
+ @typed_kwargs(
+ 'gnome.yelp',
+ KwargInfo(
+ 'languages', ContainerTypeInfo(list, str),
+ listify=True, default=[],
+ deprecated='0.43.0',
+ deprecated_message='Use a LINGUAS file in the source directory instead',
+ ),
+ KwargInfo('media', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('sources', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('symlink_media', bool, default=True),
+ )
+ def yelp(self, state: 'ModuleState', args: T.Tuple[str, T.List[str]], kwargs: 'Yelp') -> ModuleReturnValue:
+ project_id = args[0]
+ sources = kwargs['sources']
+ if args[1]:
+ FeatureDeprecated.single_use('gnome.yelp more than one positional argument', '0.60.0',
+ state.subproject, 'use the "sources" keyword argument instead.', state.current_node)
+ if not sources:
+ sources = args[1]
+ if not sources:
+ raise MesonException('Yelp requires a list of sources')
+ elif args[1]:
+ mlog.warning('"gnome.yelp" ignores positional sources arguments when the "sources" keyword argument is set')
+ sources_files = [mesonlib.File.from_source_file(state.environment.source_dir,
+ os.path.join(state.subdir, 'C'),
+ s) for s in sources]
+
+ langs = kwargs['languages']
+ if not langs:
+ langs = read_linguas(os.path.join(state.environment.source_dir, state.subdir))
+
+ media = kwargs['media']
+ symlinks = kwargs['symlink_media']
+ targets: T.List[T.Union['build.Target', build.Data, build.SymlinkData]] = []
+ potargets: T.List[build.RunTarget] = []
+
+ itstool = state.find_program('itstool')
+ msgmerge = state.find_program('msgmerge')
+ msgfmt = state.find_program('msgfmt')
+
+ install_dir = os.path.join(state.environment.get_datadir(), 'help')
+ c_install_dir = os.path.join(install_dir, 'C', project_id)
+ c_data = build.Data(sources_files, c_install_dir, c_install_dir,
+ mesonlib.FileMode(), state.subproject, install_tag='doc')
+ targets.append(c_data)
+
+ media_files: T.List[mesonlib.File] = []
+ for m in media:
+ f = mesonlib.File.from_source_file(state.environment.source_dir,
+ os.path.join(state.subdir, 'C'), m)
+ media_files.append(f)
+ m_install_dir = os.path.join(c_install_dir, os.path.dirname(m))
+ m_data = build.Data([f], m_install_dir, m_install_dir,
+ mesonlib.FileMode(), state.subproject, install_tag='doc')
+ targets.append(m_data)
+
+ pot_file = os.path.join('@SOURCE_ROOT@', state.subdir, 'C', project_id + '.pot')
+ pot_sources = [os.path.join('@SOURCE_ROOT@', state.subdir, 'C', s) for s in sources]
+ pot_args: T.List[T.Union['ExternalProgram', str]] = [itstool, '-o', pot_file]
+ pot_args.extend(pot_sources)
+ pottarget = build.RunTarget(f'help-{project_id}-pot', pot_args, [],
+ os.path.join(state.subdir, 'C'), state.subproject,
+ state.environment)
+ targets.append(pottarget)
+
+ for l in langs:
+ l_subdir = os.path.join(state.subdir, l)
+ l_install_dir = os.path.join(install_dir, l, project_id)
+
+ for i, m in enumerate(media):
+ m_dir = os.path.dirname(m)
+ m_install_dir = os.path.join(l_install_dir, m_dir)
+ l_data: T.Union[build.Data, build.SymlinkData]
+ if symlinks:
+ link_target = os.path.join(os.path.relpath(c_install_dir, start=m_install_dir), m)
+ l_data = build.SymlinkData(link_target, os.path.basename(m),
+ m_install_dir, state.subproject, install_tag='doc')
+ else:
+ try:
+ m_file = mesonlib.File.from_source_file(state.environment.source_dir, l_subdir, m)
+ except MesonException:
+ m_file = media_files[i]
+ l_data = build.Data([m_file], m_install_dir, m_install_dir,
+ mesonlib.FileMode(), state.subproject, install_tag='doc')
+ targets.append(l_data)
+
+ po_file = l + '.po'
+ po_args: T.List[T.Union['ExternalProgram', str]] = [
+ msgmerge, '-q', '-o',
+ os.path.join('@SOURCE_ROOT@', l_subdir, po_file),
+ os.path.join('@SOURCE_ROOT@', l_subdir, po_file), pot_file]
+ potarget = build.RunTarget(f'help-{project_id}-{l}-update-po',
+ po_args, [pottarget], l_subdir, state.subproject,
+ state.environment)
+ targets.append(potarget)
+ potargets.append(potarget)
+
+ gmo_file = project_id + '-' + l + '.gmo'
+ gmotarget = build.CustomTarget(
+ f'help-{project_id}-{l}-gmo',
+ l_subdir,
+ state.subproject,
+ state.environment,
+ [msgfmt, '@INPUT@', '-o', '@OUTPUT@'],
+ [po_file],
+ [gmo_file],
+ install_tag=['doc'],
+ )
+ targets.append(gmotarget)
+
+ mergetarget = build.CustomTarget(
+ f'help-{project_id}-{l}',
+ l_subdir,
+ state.subproject,
+ state.environment,
+ [itstool, '-m', os.path.join(l_subdir, gmo_file), '--lang', l, '-o', '@OUTDIR@', '@INPUT@'],
+ sources_files,
+ sources,
+ extra_depends=[gmotarget],
+ install=True,
+ install_dir=[l_install_dir],
+ install_tag=['doc'],
+ )
+ targets.append(mergetarget)
+
+ allpotarget = build.AliasTarget(f'help-{project_id}-update-po', potargets,
+ state.subdir, state.subproject, state.environment)
+ targets.append(allpotarget)
+
+ return ModuleReturnValue(None, targets)
+
+ @typed_pos_args('gnome.gtkdoc', str)
+ @typed_kwargs(
+ 'gnome.gtkdoc',
+ KwargInfo('c_args', ContainerTypeInfo(list, str), since='0.48.0', default=[], listify=True),
+ KwargInfo('check', bool, default=False, since='0.52.0'),
+ KwargInfo('content_files', ContainerTypeInfo(list, (str, mesonlib.File, build.GeneratedList, build.CustomTarget, build.CustomTargetIndex)), default=[], listify=True),
+ KwargInfo(
+ 'dependencies',
+ ContainerTypeInfo(list, (Dependency, build.SharedLibrary, build.StaticLibrary)),
+ listify=True, default=[]),
+ KwargInfo('expand_content_files', ContainerTypeInfo(list, (str, mesonlib.File)), default=[], listify=True),
+ KwargInfo('fixxref_args', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('gobject_typesfile', ContainerTypeInfo(list, (str, mesonlib.File)), default=[], listify=True),
+ KwargInfo('html_args', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('html_assets', ContainerTypeInfo(list, (str, mesonlib.File)), default=[], listify=True),
+ KwargInfo('ignore_headers', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo(
+ 'include_directories',
+ ContainerTypeInfo(list, (str, build.IncludeDirs)),
+ listify=True, default=[]),
+ KwargInfo('install', bool, default=True),
+ KwargInfo('install_dir', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('main_sgml', (str, NoneType)),
+ KwargInfo('main_xml', (str, NoneType)),
+ KwargInfo('mkdb_args', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo(
+ 'mode', str, default='auto', since='0.37.0',
+ validator=in_set_validator({'xml', 'sgml', 'none', 'auto'})),
+ KwargInfo('module_version', str, default='', since='0.48.0'),
+ KwargInfo('namespace', str, default='', since='0.37.0'),
+ KwargInfo('scan_args', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('scanobjs_args', ContainerTypeInfo(list, str), default=[], listify=True),
+ KwargInfo('src_dir', ContainerTypeInfo(list, (str, build.IncludeDirs)), listify=True, required=True),
+ )
+ def gtkdoc(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'GtkDoc') -> ModuleReturnValue:
+ modulename = args[0]
+ main_file = kwargs['main_sgml']
+ main_xml = kwargs['main_xml']
+ if main_xml is not None:
+ if main_file is not None:
+ raise InvalidArguments('gnome.gtkdoc: main_xml and main_sgml are exclusive arguments')
+ main_file = main_xml
+ moduleversion = kwargs['module_version']
+ targetname = modulename + ('-' + moduleversion if moduleversion else '') + '-doc'
+ command = state.environment.get_build_command()
+
+ namespace = kwargs['namespace']
+
+ def abs_filenames(files: T.Iterable['FileOrString']) -> T.Iterator[str]:
+ for f in files:
+ if isinstance(f, mesonlib.File):
+ yield f.absolute_path(state.environment.get_source_dir(), state.environment.get_build_dir())
+ else:
+ yield os.path.join(state.environment.get_source_dir(), state.subdir, f)
+
+ src_dirs = kwargs['src_dir']
+ header_dirs: T.List[str] = []
+ for src_dir in src_dirs:
+ if isinstance(src_dir, build.IncludeDirs):
+ header_dirs.extend(src_dir.to_string_list(state.environment.get_source_dir(),
+ state.environment.get_build_dir()))
+ else:
+ header_dirs.append(src_dir)
+
+ t_args: T.List[str] = [
+ '--internal', 'gtkdoc',
+ '--sourcedir=' + state.environment.get_source_dir(),
+ '--builddir=' + state.environment.get_build_dir(),
+ '--subdir=' + state.subdir,
+ '--headerdirs=' + '@@'.join(header_dirs),
+ '--mainfile=' + main_file,
+ '--modulename=' + modulename,
+ '--moduleversion=' + moduleversion,
+ '--mode=' + kwargs['mode']]
+ for tool in ['scan', 'scangobj', 'mkdb', 'mkhtml', 'fixxref']:
+ program_name = 'gtkdoc-' + tool
+ program = state.find_program(program_name)
+ path = program.get_path()
+ t_args.append(f'--{program_name}={path}')
+ if namespace:
+ t_args.append('--namespace=' + namespace)
+ exe_wrapper = state.environment.get_exe_wrapper()
+ if exe_wrapper:
+ t_args.append('--run=' + ' '.join(exe_wrapper.get_command()))
+ t_args.append(f'--htmlargs={"@@".join(kwargs["html_args"])}')
+ t_args.append(f'--scanargs={"@@".join(kwargs["scan_args"])}')
+ t_args.append(f'--scanobjsargs={"@@".join(kwargs["scanobjs_args"])}')
+ t_args.append(f'--gobjects-types-file={"@@".join(abs_filenames(kwargs["gobject_typesfile"]))}')
+ t_args.append(f'--fixxrefargs={"@@".join(kwargs["fixxref_args"])}')
+ t_args.append(f'--mkdbargs={"@@".join(kwargs["mkdb_args"])}')
+ t_args.append(f'--html-assets={"@@".join(abs_filenames(kwargs["html_assets"]))}')
+
+ depends: T.List['build.GeneratedTypes'] = []
+ content_files = []
+ for s in kwargs['content_files']:
+ if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)):
+ depends.append(s)
+ for o in s.get_outputs():
+ content_files.append(os.path.join(state.environment.get_build_dir(),
+ state.backend.get_target_dir(s),
+ o))
+ elif isinstance(s, mesonlib.File):
+ content_files.append(s.absolute_path(state.environment.get_source_dir(),
+ state.environment.get_build_dir()))
+ elif isinstance(s, build.GeneratedList):
+ depends.append(s)
+ for gen_src in s.get_outputs():
+ content_files.append(os.path.join(state.environment.get_source_dir(),
+ state.subdir,
+ gen_src))
+ else:
+ content_files.append(os.path.join(state.environment.get_source_dir(),
+ state.subdir,
+ s))
+ t_args += ['--content-files=' + '@@'.join(content_files)]
+
+ t_args.append(f'--expand-content-files={"@@".join(abs_filenames(kwargs["expand_content_files"]))}')
+ t_args.append(f'--ignore-headers={"@@".join(kwargs["ignore_headers"])}')
+ t_args.append(f'--installdir={"@@".join(kwargs["install_dir"])}')
+ build_args, new_depends = self._get_build_args(kwargs['c_args'], kwargs['include_directories'],
+ kwargs['dependencies'], state, depends)
+ t_args.extend(build_args)
+ new_depends.extend(depends)
+ custom_target = build.CustomTarget(
+ targetname,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ command + t_args,
+ [],
+ [f'{modulename}-decl.txt'],
+ build_always_stale=True,
+ extra_depends=new_depends,
+ )
+ alias_target = build.AliasTarget(targetname, [custom_target], state.subdir, state.subproject, state.environment)
+ if kwargs['check']:
+ check_cmd = state.find_program('gtkdoc-check')
+ check_env = ['DOC_MODULE=' + modulename,
+ 'DOC_MAIN_SGML_FILE=' + main_file]
+ check_args = (targetname + '-check', check_cmd)
+ check_workdir = os.path.join(state.environment.get_build_dir(), state.subdir)
+ state.test(check_args, env=check_env, workdir=check_workdir, depends=[custom_target])
+ res: T.List[T.Union[build.Target, build.ExecutableSerialisation]] = [custom_target, alias_target]
+ if kwargs['install']:
+ res.append(state.backend.get_executable_serialisation(command + t_args, tag='doc'))
+ return ModuleReturnValue(custom_target, res)
+
+ def _get_build_args(self, c_args: T.List[str], inc_dirs: T.List[T.Union[str, build.IncludeDirs]],
+ deps: T.List[T.Union[Dependency, build.SharedLibrary, build.StaticLibrary]],
+ state: 'ModuleState',
+ depends: T.Sequence[T.Union[build.BuildTarget, 'build.GeneratedTypes']]) -> T.Tuple[
+ T.List[str], T.List[T.Union[build.BuildTarget, 'build.GeneratedTypes', 'FileOrString', build.StructuredSources]]]:
+ args: T.List[str] = []
+ cflags = c_args.copy()
+ deps_cflags, internal_ldflags, external_ldflags, _gi_includes, new_depends = \
+ self._get_dependencies_flags(deps, state, depends, include_rpath=True)
+
+ cflags.extend(deps_cflags)
+ cflags.extend(state.get_include_args(inc_dirs))
+ ldflags: T.List[str] = []
+ ldflags.extend(internal_ldflags)
+ ldflags.extend(external_ldflags)
+
+ cflags.extend(state.environment.coredata.get_external_args(MachineChoice.HOST, 'c'))
+ ldflags.extend(state.environment.coredata.get_external_link_args(MachineChoice.HOST, 'c'))
+ compiler = state.environment.coredata.compilers[MachineChoice.HOST]['c']
+
+ compiler_flags = self._get_langs_compilers_flags(state, [('c', compiler)])
+ cflags.extend(compiler_flags[0])
+ ldflags.extend(compiler_flags[1])
+ ldflags.extend(compiler_flags[2])
+ if compiler:
+ args += ['--cc=%s' % join_args(compiler.get_exelist())]
+ args += ['--ld=%s' % join_args(compiler.get_linker_exelist())]
+ if cflags:
+ args += ['--cflags=%s' % join_args(cflags)]
+ if ldflags:
+ args += ['--ldflags=%s' % join_args(ldflags)]
+
+ return args, new_depends
+
+ @noKwargs
+ @typed_pos_args('gnome.gtkdoc_html_dir', str)
+ def gtkdoc_html_dir(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> str:
+ return os.path.join('share/gtk-doc/html', args[0])
+
+ @typed_pos_args('gnome.gdbus_codegen', str, optargs=[(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)])
+ @typed_kwargs(
+ 'gnome.gdbus_codegen',
+ _BUILD_BY_DEFAULT.evolve(since='0.40.0'),
+ SOURCES_KW.evolve(since='0.46.0'),
+ KwargInfo('extra_args', ContainerTypeInfo(list, str), since='0.47.0', default=[], listify=True),
+ KwargInfo('interface_prefix', (str, NoneType)),
+ KwargInfo('namespace', (str, NoneType)),
+ KwargInfo('object_manager', bool, default=False),
+ KwargInfo(
+ 'annotations', ContainerTypeInfo(list, (list, str)),
+ default=[],
+ validator=annotations_validator,
+ convertor=lambda x: [x] if x and isinstance(x[0], str) else x,
+ ),
+ KwargInfo('install_header', bool, default=False, since='0.46.0'),
+ KwargInfo('docbook', (str, NoneType)),
+ KwargInfo(
+ 'autocleanup', str, default='default', since='0.47.0',
+ validator=in_set_validator({'all', 'none', 'objects'})),
+ INSTALL_DIR_KW.evolve(since='0.46.0')
+ )
+ def gdbus_codegen(self, state: 'ModuleState', args: T.Tuple[str, T.Optional[T.Union['FileOrString', build.GeneratedTypes]]],
+ kwargs: 'GdbusCodegen') -> ModuleReturnValue:
+ namebase = args[0]
+ xml_files: T.List[T.Union['FileOrString', build.GeneratedTypes]] = [args[1]] if args[1] else []
+ cmd: T.List[T.Union['ExternalProgram', str]] = [state.find_program('gdbus-codegen')]
+ cmd.extend(kwargs['extra_args'])
+
+ # Autocleanup supported?
+ glib_version = self._get_native_glib_version(state)
+ if not mesonlib.version_compare(glib_version, '>= 2.49.1'):
+ # Warn if requested, silently disable if not
+ if kwargs['autocleanup'] != 'default':
+ mlog.warning(f'Glib version ({glib_version}) is too old to support the \'autocleanup\' '
+ 'kwarg, need 2.49.1 or newer')
+ else:
+ # Handle legacy glib versions that don't have autocleanup
+ ac = kwargs['autocleanup']
+ if ac == 'default':
+ ac = 'all'
+ cmd.extend(['--c-generate-autocleanup', ac])
+
+ if kwargs['interface_prefix'] is not None:
+ cmd.extend(['--interface-prefix', kwargs['interface_prefix']])
+ if kwargs['namespace'] is not None:
+ cmd.extend(['--c-namespace', kwargs['namespace']])
+ if kwargs['object_manager']:
+ cmd.extend(['--c-generate-object-manager'])
+ xml_files.extend(kwargs['sources'])
+ build_by_default = kwargs['build_by_default']
+
+ # Annotations are a bit ugly in that they are a list of lists of strings...
+ for annot in kwargs['annotations']:
+ cmd.append('--annotate')
+ cmd.extend(annot)
+
+ targets = []
+ install_header = kwargs['install_header']
+ install_dir = kwargs['install_dir'] or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
+ assert isinstance(install_dir, str), 'for mypy'
+
+ output = namebase + '.c'
+ # Added in https://gitlab.gnome.org/GNOME/glib/commit/e4d68c7b3e8b01ab1a4231bf6da21d045cb5a816 (2.55.2)
+ # Fixed in https://gitlab.gnome.org/GNOME/glib/commit/cd1f82d8fc741a2203582c12cc21b4dacf7e1872 (2.56.2)
+ if mesonlib.version_compare(glib_version, '>= 2.56.2'):
+ c_cmd = cmd + ['--body', '--output', '@OUTPUT@', '@INPUT@']
+ else:
+ if kwargs['docbook'] is not None:
+ docbook = kwargs['docbook']
+
+ cmd += ['--generate-docbook', docbook]
+
+ # https://git.gnome.org/browse/glib/commit/?id=ee09bb704fe9ccb24d92dd86696a0e6bb8f0dc1a
+ if mesonlib.version_compare(glib_version, '>= 2.51.3'):
+ cmd += ['--output-directory', '@OUTDIR@', '--generate-c-code', namebase, '@INPUT@']
+ else:
+ self._print_gdbus_warning()
+ cmd += ['--generate-c-code', '@OUTDIR@/' + namebase, '@INPUT@']
+ c_cmd = cmd
+
+ cfile_custom_target = build.CustomTarget(
+ output,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ c_cmd,
+ xml_files,
+ [output],
+ build_by_default=build_by_default,
+ )
+ targets.append(cfile_custom_target)
+
+ output = namebase + '.h'
+ if mesonlib.version_compare(glib_version, '>= 2.56.2'):
+ hfile_cmd = cmd + ['--header', '--output', '@OUTPUT@', '@INPUT@']
+ depends = []
+ else:
+ hfile_cmd = cmd
+ depends = [cfile_custom_target]
+
+ hfile_custom_target = build.CustomTarget(
+ output,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ hfile_cmd,
+ xml_files,
+ [output],
+ build_by_default=build_by_default,
+ extra_depends=depends,
+ install=install_header,
+ install_dir=[install_dir],
+ install_tag=['devel'],
+ )
+ targets.append(hfile_custom_target)
+
+ if kwargs['docbook'] is not None:
+ docbook = kwargs['docbook']
+ # The docbook output is always ${docbook}-${name_of_xml_file}
+ output = namebase + '-docbook'
+ outputs = []
+ for f in xml_files:
+ outputs.append('{}-{}'.format(docbook, os.path.basename(str(f))))
+
+ if mesonlib.version_compare(glib_version, '>= 2.56.2'):
+ docbook_cmd = cmd + ['--output-directory', '@OUTDIR@', '--generate-docbook', docbook, '@INPUT@']
+ depends = []
+ else:
+ docbook_cmd = cmd
+ depends = [cfile_custom_target]
+
+ docbook_custom_target = build.CustomTarget(
+ output,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ docbook_cmd,
+ xml_files,
+ outputs,
+ build_by_default=build_by_default,
+ extra_depends=depends,
+ )
+ targets.append(docbook_custom_target)
+
+ return ModuleReturnValue(targets, targets)
+
+ @typed_pos_args('gnome.mkenums', str)
+ @typed_kwargs(
+ 'gnome.mkenums',
+ *_MK_ENUMS_COMMON_KWS,
+ DEPENDS_KW,
+ KwargInfo('c_template', (str, mesonlib.File, NoneType)),
+ KwargInfo('h_template', (str, mesonlib.File, NoneType)),
+ KwargInfo('comments', (str, NoneType)),
+ KwargInfo('eprod', (str, NoneType)),
+ KwargInfo('fhead', (str, NoneType)),
+ KwargInfo('fprod', (str, NoneType)),
+ KwargInfo('ftail', (str, NoneType)),
+ KwargInfo('vhead', (str, NoneType)),
+ KwargInfo('vprod', (str, NoneType)),
+ KwargInfo('vtail', (str, NoneType)),
+ )
+ def mkenums(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'MkEnums') -> ModuleReturnValue:
+ basename = args[0]
+
+ c_template = kwargs['c_template']
+ if isinstance(c_template, mesonlib.File):
+ c_template = c_template.absolute_path(state.environment.source_dir, state.environment.build_dir)
+ h_template = kwargs['h_template']
+ if isinstance(h_template, mesonlib.File):
+ h_template = h_template.absolute_path(state.environment.source_dir, state.environment.build_dir)
+
+ cmd: T.List[str] = []
+ known_kwargs = ['comments', 'eprod', 'fhead', 'fprod', 'ftail',
+ 'identifier_prefix', 'symbol_prefix',
+ 'vhead', 'vprod', 'vtail']
+ for arg in known_kwargs:
+ # mypy can't figure this out
+ if kwargs[arg]: # type: ignore
+ cmd += ['--' + arg.replace('_', '-'), kwargs[arg]] # type: ignore
+
+ targets: T.List[CustomTarget] = []
+
+ h_target: T.Optional[CustomTarget] = None
+ if h_template is not None:
+ h_output = os.path.basename(os.path.splitext(h_template)[0])
+ # We always set template as the first element in the source array
+ # so --template consumes it.
+ h_cmd = cmd + ['--template', '@INPUT@']
+ h_sources: T.List[T.Union[FileOrString, 'build.GeneratedTypes']] = [h_template]
+ h_sources.extend(kwargs['sources'])
+ h_target = self._make_mkenum_impl(
+ state, h_sources, h_output, h_cmd, install=kwargs['install_header'],
+ install_dir=kwargs['install_dir'])
+ targets.append(h_target)
+
+ if c_template is not None:
+ c_output = os.path.basename(os.path.splitext(c_template)[0])
+ # We always set template as the first element in the source array
+ # so --template consumes it.
+ c_cmd = cmd + ['--template', '@INPUT@']
+ c_sources: T.List[T.Union[FileOrString, 'build.GeneratedTypes']] = [c_template]
+ c_sources.extend(kwargs['sources'])
+
+ depends = kwargs['depends'].copy()
+ if h_target is not None:
+ depends.append(h_target)
+ c_target = self._make_mkenum_impl(
+ state, c_sources, c_output, c_cmd, depends=depends)
+ targets.insert(0, c_target)
+
+ if c_template is None and h_template is None:
+ generic_cmd = cmd + ['@INPUT@']
+ target = self._make_mkenum_impl(
+ state, kwargs['sources'], basename, generic_cmd,
+ install=kwargs['install_header'],
+ install_dir=kwargs['install_dir'])
+ return ModuleReturnValue(target, [target])
+ else:
+ return ModuleReturnValue(targets, targets)
+
+ @FeatureNew('gnome.mkenums_simple', '0.42.0')
+ @typed_pos_args('gnome.mkenums_simple', str)
+ @typed_kwargs(
+ 'gnome.mkenums_simple',
+ *_MK_ENUMS_COMMON_KWS,
+ KwargInfo('header_prefix', str, default=''),
+ KwargInfo('function_prefix', str, default=''),
+ KwargInfo('body_prefix', str, default=''),
+ KwargInfo('decorator', str, default=''),
+ )
+ def mkenums_simple(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'MkEnumsSimple') -> ModuleReturnValue:
+ hdr_filename = f'{args[0]}.h'
+ body_filename = f'{args[0]}.c'
+
+ header_prefix = kwargs['header_prefix']
+ decl_decorator = kwargs['decorator']
+ func_prefix = kwargs['function_prefix']
+ body_prefix = kwargs['body_prefix']
+
+ cmd: T.List[str] = []
+ if kwargs['identifier_prefix']:
+ cmd.extend(['--identifier-prefix', kwargs['identifier_prefix']])
+ if kwargs['symbol_prefix']:
+ cmd.extend(['--symbol-prefix', kwargs['symbol_prefix']])
+
+ c_cmd = cmd.copy()
+ # Maybe we should write our own template files into the build dir
+ # instead, but that seems like much more work, nice as it would be.
+ fhead = ''
+ if body_prefix != '':
+ fhead += '%s\n' % body_prefix
+ fhead += '#include "%s"\n' % hdr_filename
+ for hdr in kwargs['sources']:
+ fhead += '#include "{}"\n'.format(os.path.basename(str(hdr)))
+ fhead += textwrap.dedent(
+ '''
+ #define C_ENUM(v) ((gint) v)
+ #define C_FLAGS(v) ((guint) v)
+ ''')
+ c_cmd.extend(['--fhead', fhead])
+
+ c_cmd.append('--fprod')
+ c_cmd.append(textwrap.dedent(
+ '''
+ /* enumerations from "@basename@" */
+ '''))
+
+ c_cmd.append('--vhead')
+ c_cmd.append(textwrap.dedent(
+ f'''
+ GType
+ {func_prefix}@enum_name@_get_type (void)
+ {{
+ static gsize gtype_id = 0;
+ static const G@Type@Value values[] = {{'''))
+
+ c_cmd.extend(['--vprod', ' { C_@TYPE@(@VALUENAME@), "@VALUENAME@", "@valuenick@" },'])
+
+ c_cmd.append('--vtail')
+ c_cmd.append(textwrap.dedent(
+ ''' { 0, NULL, NULL }
+ };
+ if (g_once_init_enter (&gtype_id)) {
+ GType new_type = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
+ g_once_init_leave (&gtype_id, new_type);
+ }
+ return (GType) gtype_id;
+ }'''))
+ c_cmd.append('@INPUT@')
+
+ c_file = self._make_mkenum_impl(state, kwargs['sources'], body_filename, c_cmd)
+
+ # .h file generation
+ h_cmd = cmd.copy()
+
+ h_cmd.append('--fhead')
+ h_cmd.append(textwrap.dedent(
+ f'''#pragma once
+
+ #include <glib-object.h>
+ {header_prefix}
+
+ G_BEGIN_DECLS
+ '''))
+
+ h_cmd.append('--fprod')
+ h_cmd.append(textwrap.dedent(
+ '''
+ /* enumerations from "@basename@" */
+ '''))
+
+ h_cmd.append('--vhead')
+ h_cmd.append(textwrap.dedent(
+ f'''
+ {decl_decorator}
+ GType {func_prefix}@enum_name@_get_type (void);
+ #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ ({func_prefix}@enum_name@_get_type())'''))
+
+ h_cmd.append('--ftail')
+ h_cmd.append(textwrap.dedent(
+ '''
+ G_END_DECLS'''))
+ h_cmd.append('@INPUT@')
+
+ h_file = self._make_mkenum_impl(
+ state, kwargs['sources'], hdr_filename, h_cmd,
+ install=kwargs['install_header'],
+ install_dir=kwargs['install_dir'])
+
+ return ModuleReturnValue([c_file, h_file], [c_file, h_file])
+
+ @staticmethod
+ def _make_mkenum_impl(
+ state: 'ModuleState',
+ sources: T.Sequence[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]],
+ output: str,
+ cmd: T.List[str],
+ *,
+ install: bool = False,
+ install_dir: T.Optional[T.Sequence[T.Union[str, bool]]] = None,
+ depends: T.Optional[T.Sequence[T.Union[CustomTarget, CustomTargetIndex, BuildTarget]]] = None
+ ) -> build.CustomTarget:
+ real_cmd: T.List[T.Union[str, ExternalProgram]] = [state.find_program(['glib-mkenums', 'mkenums'])]
+ real_cmd.extend(cmd)
+ _install_dir = install_dir or state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))
+ assert isinstance(_install_dir, str), 'for mypy'
+
+ return build.CustomTarget(
+ output,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ real_cmd,
+ sources,
+ [output],
+ capture=True,
+ install=install,
+ install_dir=[_install_dir],
+ install_tag=['devel'],
+ extra_depends=depends,
+ # https://github.com/mesonbuild/meson/issues/973
+ absolute_paths=True,
+ )
+
+ @typed_pos_args('gnome.genmarshal', str)
+ @typed_kwargs(
+ 'gnome.genmarshal',
+ DEPEND_FILES_KW.evolve(since='0.61.0'),
+ DEPENDS_KW.evolve(since='0.61.0'),
+ INSTALL_KW.evolve(name='install_header'),
+ INSTALL_DIR_KW,
+ KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('internal', bool, default=False),
+ KwargInfo('nostdinc', bool, default=False),
+ KwargInfo('prefix', (str, NoneType)),
+ KwargInfo('skip_source', bool, default=False),
+ KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File), allow_empty=False), listify=True, required=True),
+ KwargInfo('stdinc', bool, default=False),
+ KwargInfo('valist_marshallers', bool, default=False),
+ )
+ def genmarshal(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'GenMarshal') -> ModuleReturnValue:
+ output = args[0]
+ sources = kwargs['sources']
+
+ new_genmarshal = mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.3')
+
+ cmd: T.List[T.Union['ExternalProgram', str]] = [state.find_program('glib-genmarshal')]
+ if kwargs['prefix']:
+ cmd.extend(['--prefix', kwargs['prefix']])
+ if kwargs['extra_args']:
+ if new_genmarshal:
+ cmd.extend(kwargs['extra_args'])
+ else:
+ mlog.warning('The current version of GLib does not support extra arguments \n'
+ 'for glib-genmarshal. You need at least GLib 2.53.3. See ',
+ mlog.bold('https://github.com/mesonbuild/meson/pull/2049'))
+ for k in ['internal', 'nostdinc', 'skip_source', 'stdinc', 'valist_marshallers']:
+ # Mypy can't figure out that this is correct
+ if kwargs[k]: # type: ignore
+ cmd.append(f'--{k.replace("_", "-")}')
+
+ install_header = kwargs['install_header']
+ capture = False
+
+ # https://github.com/GNOME/glib/commit/0fbc98097fac4d3e647684f344e508abae109fdf
+ if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.0'):
+ cmd += ['--output', '@OUTPUT@']
+ else:
+ capture = True
+
+ header_file = output + '.h'
+ h_cmd = cmd + ['--header', '@INPUT@']
+ if new_genmarshal:
+ h_cmd += ['--pragma-once']
+ header = build.CustomTarget(
+ output + '_h',
+ state.subdir,
+ state.subproject,
+ state.environment,
+ h_cmd,
+ sources,
+ [header_file],
+ install=install_header,
+ install_dir=[kwargs['install_dir']] if kwargs['install_dir'] else [],
+ install_tag=['devel'],
+ capture=capture,
+ depend_files=kwargs['depend_files'],
+ )
+
+ c_cmd = cmd + ['--body', '@INPUT@']
+ extra_deps: T.List[build.CustomTarget] = []
+ if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.53.4'):
+ # Silence any warnings about missing prototypes
+ c_cmd += ['--include-header', header_file]
+ extra_deps.append(header)
+ body = build.CustomTarget(
+ output + '_c',
+ state.subdir,
+ state.subproject,
+ state.environment,
+ c_cmd,
+ sources,
+ [f'{output}.c'],
+ capture=capture,
+ depend_files=kwargs['depend_files'],
+ extra_depends=extra_deps,
+ )
+
+ rv = [body, header]
+ return ModuleReturnValue(rv, rv)
+
+ def _extract_vapi_packages(self, state: 'ModuleState', packages: T.List[T.Union[InternalDependency, str]],
+ ) -> T.Tuple[T.List[str], T.List[VapiTarget], T.List[str], T.List[str], T.List[str]]:
+ '''
+ Packages are special because we need to:
+ - Get a list of packages for the .deps file
+ - Get a list of depends for any VapiTargets
+ - Get package name from VapiTargets
+ - Add include dirs for any VapiTargets
+ '''
+ if not packages:
+ return [], [], [], [], []
+ vapi_depends: T.List[VapiTarget] = []
+ vapi_packages: T.List[str] = []
+ vapi_includes: T.List[str] = []
+ vapi_args: T.List[str] = []
+ remaining_args = []
+ for arg in packages:
+ if isinstance(arg, InternalDependency):
+ targets = [t for t in arg.sources if isinstance(t, VapiTarget)]
+ for target in targets:
+ srcdir = os.path.join(state.environment.get_source_dir(),
+ target.get_subdir())
+ outdir = os.path.join(state.environment.get_build_dir(),
+ target.get_subdir())
+ outfile = target.get_outputs()[0][:-5] # Strip .vapi
+ vapi_args.append('--vapidir=' + outdir)
+ vapi_args.append('--girdir=' + outdir)
+ vapi_args.append('--pkg=' + outfile)
+ vapi_depends.append(target)
+ vapi_packages.append(outfile)
+ vapi_includes.append(srcdir)
+ else:
+ assert isinstance(arg, str), 'for mypy'
+ vapi_args.append(f'--pkg={arg}')
+ vapi_packages.append(arg)
+ remaining_args.append(arg)
+
+ # TODO: this is supposed to take IncludeDirs, but it never worked
+ return vapi_args, vapi_depends, vapi_packages, vapi_includes, remaining_args
+
+ def _generate_deps(self, state: 'ModuleState', library: str, packages: T.List[str], install_dir: str) -> build.Data:
+ outdir = state.environment.scratch_dir
+ fname = os.path.join(outdir, library + '.deps')
+ with open(fname, 'w', encoding='utf-8') as ofile:
+ for package in packages:
+ ofile.write(package + '\n')
+ return build.Data([mesonlib.File(True, outdir, fname)], install_dir, install_dir, mesonlib.FileMode(), state.subproject)
+
+ def _get_vapi_link_with(self, target: build.CustomTarget) -> T.List[build.LibTypes]:
+ link_with: T.List[build.LibTypes] = []
+ for dep in target.get_target_dependencies():
+ if isinstance(dep, build.SharedLibrary):
+ link_with.append(dep)
+ elif isinstance(dep, GirTarget):
+ link_with += self._get_vapi_link_with(dep)
+ return link_with
+
+ @typed_pos_args('gnome.generate_vapi', str)
+ @typed_kwargs(
+ 'gnome.generate_vapi',
+ INSTALL_KW,
+ INSTALL_DIR_KW,
+ KwargInfo(
+ 'sources',
+ ContainerTypeInfo(list, (str, GirTarget), allow_empty=False),
+ listify=True,
+ required=True,
+ ),
+ KwargInfo('vapi_dirs', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('metadata_dirs', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('gir_dirs', ContainerTypeInfo(list, str), listify=True, default=[]),
+ KwargInfo('packages', ContainerTypeInfo(list, (str, InternalDependency)), listify=True, default=[]),
+ )
+ def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'GenerateVapi') -> ModuleReturnValue:
+ created_values: T.List[T.Union[Dependency, build.Data]] = []
+ library = args[0]
+ build_dir = os.path.join(state.environment.get_build_dir(), state.subdir)
+ source_dir = os.path.join(state.environment.get_source_dir(), state.subdir)
+ pkg_cmd, vapi_depends, vapi_packages, vapi_includes, packages = self._extract_vapi_packages(state, kwargs['packages'])
+ cmd: T.List[T.Union[str, 'ExternalProgram']]
+ cmd = [state.find_program('vapigen'), '--quiet', f'--library={library}', f'--directory={build_dir}']
+ cmd.extend([f'--vapidir={d}' for d in kwargs['vapi_dirs']])
+ cmd.extend([f'--metadatadir={d}' for d in kwargs['metadata_dirs']])
+ cmd.extend([f'--girdir={d}' for d in kwargs['gir_dirs']])
+ cmd += pkg_cmd
+ cmd += ['--metadatadir=' + source_dir]
+
+ inputs = kwargs['sources']
+
+ link_with: T.List[build.LibTypes] = []
+ for i in inputs:
+ if isinstance(i, str):
+ cmd.append(os.path.join(source_dir, i))
+ elif isinstance(i, GirTarget):
+ link_with += self._get_vapi_link_with(i)
+ subdir = os.path.join(state.environment.get_build_dir(),
+ i.get_subdir())
+ gir_file = os.path.join(subdir, i.get_outputs()[0])
+ cmd.append(gir_file)
+
+ vapi_output = library + '.vapi'
+ datadir = state.environment.coredata.get_option(mesonlib.OptionKey('datadir'))
+ assert isinstance(datadir, str), 'for mypy'
+ install_dir = kwargs['install_dir'] or os.path.join(datadir, 'vala', 'vapi')
+
+ if kwargs['install']:
+ # We shouldn't need this locally but we install it
+ deps_target = self._generate_deps(state, library, vapi_packages, install_dir)
+ created_values.append(deps_target)
+ vapi_target = VapiTarget(
+ vapi_output,
+ state.subdir,
+ state.subproject,
+ state.environment,
+ command=cmd,
+ sources=inputs,
+ outputs=[vapi_output],
+ extra_depends=vapi_depends,
+ install=kwargs['install'],
+ install_dir=[install_dir],
+ install_tag=['devel'],
+ )
+
+ # So to try our best to get this to just work we need:
+ # - link with with the correct library
+ # - include the vapi and dependent vapi files in sources
+ # - add relevant directories to include dirs
+ incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False)]
+ sources = [vapi_target] + vapi_depends
+ rv = InternalDependency(None, incs, [], [], link_with, [], sources, [], {}, [], [])
+ created_values.append(rv)
+ return ModuleReturnValue(rv, created_values)
+
+def initialize(interp: 'Interpreter') -> GnomeModule:
+ mod = GnomeModule(interp)
+ mod.interpreter.append_holder_map(GResourceTarget, interpreter.CustomTargetHolder)
+ mod.interpreter.append_holder_map(GResourceHeaderTarget, interpreter.CustomTargetHolder)
+ mod.interpreter.append_holder_map(GirTarget, interpreter.CustomTargetHolder)
+ mod.interpreter.append_holder_map(TypelibTarget, interpreter.CustomTargetHolder)
+ mod.interpreter.append_holder_map(VapiTarget, interpreter.CustomTargetHolder)
+ return mod