Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions mesonbuild/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,15 @@ def find_program(self, prog: T.Union[mesonlib.FileOrString, T.List[mesonlib.File
wanted=wanted, silent=silent, for_machine=for_machine)

def find_tool(self, name: str, depname: str, varname: str, required: bool = True,
wanted: T.Optional[str] = None) -> T.Union[build.OverrideExecutable, ExternalProgram, 'OverrideProgram']:
# Look in overrides in case it's built as subproject
progobj = self._interpreter.program_from_overrides([name], [])
if progobj is not None:
return progobj
wanted: T.Optional[str] = None, for_machine: MachineChoice = MachineChoice.HOST) -> T.Union[build.OverrideExecutable, ExternalProgram, 'OverrideProgram']:
if for_machine is MachineChoice.HOST:
# Look in overrides in case it's built as subproject
progobj = self._interpreter.program_from_overrides([name], [])
if progobj is not None:
return progobj

# Look in machine file
prog_list = self.environment.lookup_binary_entry(MachineChoice.HOST, name)
prog_list = self.environment.lookup_binary_entry(for_machine, name)
if prog_list is not None:
return ExternalProgram.from_entry(name, prog_list)

Expand All @@ -106,7 +107,7 @@ def find_tool(self, name: str, depname: str, varname: str, required: bool = True
return progobj

# Normal program lookup
return self.find_program(name, required=required, wanted=wanted)
return self.find_program(name, required=required, wanted=wanted, for_machine=for_machine)

def dependency(self, depname: str, native: bool = False, required: bool = True,
wanted: T.Optional[str] = None) -> 'Dependency':
Expand Down
81 changes: 64 additions & 17 deletions mesonbuild/modules/gnome.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .. import interpreter
from .. import mesonlib
from .. import mlog
from ..build import CustomTarget, CustomTargetIndex, Executable, GeneratedList, InvalidArguments
from ..build import CustomTarget, CustomTargetIndex, Executable, GeneratedList, InvalidArguments, OverrideExecutable
from ..dependencies import Dependency, InternalDependency
from ..dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface
from ..interpreter.type_checking import DEPENDS_KW, DEPEND_FILES_KW, ENV_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType, DEPENDENCY_SOURCES_KW, in_set_validator
Expand All @@ -33,7 +33,7 @@
MachineChoice, MesonException, OrderedSet, Popen_safe, join_args, quote_arg
)
from ..options import OptionKey
from ..programs import OverrideProgram
from ..programs import ExternalProgram, OverrideProgram
from ..scripts.gettext import read_linguas

if T.TYPE_CHECKING:
Expand All @@ -45,7 +45,6 @@
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
Expand Down Expand Up @@ -198,7 +197,7 @@ class MkEnums(_MkEnumsCommon):
vtail: T.Optional[str]
depends: T.List[T.Union[BuildTarget, CustomTarget, CustomTargetIndex]]

ToolType: TypeAlias = T.Union[Executable, ExternalProgram, OverrideProgram]
ToolType: TypeAlias = T.Union[OverrideExecutable, ExternalProgram, OverrideProgram]


# Differs from the CustomTarget version in that it straight defaults to True
Expand Down Expand Up @@ -255,8 +254,8 @@ class GnomeModule(ExtensionModule):

def __init__(self, interpreter: 'Interpreter') -> None:
super().__init__(interpreter)
self.gir_dep: T.Optional[Dependency] = None
self.giscanner: T.Optional[ToolType] = None
self.giscanner_extra: T.List[Dependency] = []
self.gicompiler: T.Optional[ToolType] = None
self.install_glib_compile_schemas = False
self.install_gio_querymodules: T.List[str] = []
Expand Down Expand Up @@ -309,7 +308,7 @@ def _print_gdbus_warning() -> None:
once=True, fatal=False)

@staticmethod
def _find_tool(state: 'ModuleState', tool: str) -> 'ToolType':
def _find_tool(state: 'ModuleState', tool: str, for_machine: MachineChoice = MachineChoice.HOST) -> 'ToolType':
tool_map = {
'gio-querymodules': 'gio-2.0',
'glib-compile-schemas': 'gio-2.0',
Expand All @@ -322,7 +321,7 @@ def _find_tool(state: 'ModuleState', tool: str) -> 'ToolType':
}
depname = tool_map[tool]
varname = tool.replace('-', '_')
return state.find_tool(tool, depname, varname)
return state.find_tool(tool, depname, varname, for_machine=for_machine)

@typed_kwargs(
'gnome.post_install',
Expand Down Expand Up @@ -789,20 +788,26 @@ def postconf_hook(self, b: build.Build) -> None:
if self.devenv is not None:
b.devenv.append(self.devenv)

def _get_gir_dep(self, state: 'ModuleState') -> T.Tuple[Dependency, T.Union[Executable, 'ExternalProgram', 'OverrideProgram'],
T.Union[Executable, 'ExternalProgram', 'OverrideProgram']]:
if not self.gir_dep:
self.gir_dep = state.dependency('gobject-introspection-1.0')
def _get_gi(self, state: 'ModuleState') -> T.Tuple[ToolType, T.List[Dependency], ToolType]:
if not self.giscanner:
self.giscanner = self._find_tool(state, 'g-ir-scanner')
self.gicompiler = self._find_tool(state, 'g-ir-compiler')
return self.gir_dep, self.giscanner, self.gicompiler
if isinstance(self.giscanner, OverrideProgram):
# The gobject-introspection subproject just registers g-ir-scanner
# as a python script, with meson unaware of the native module the
# script depends upton that has to be built first. If g-i was
# configured with the right option, the gobject-introspection-1.0
# dependency itself indirectly depends on the native module; so if
# g-ir-scanner originates from a subproject, also add the g-i dep.
self.giscanner_extra.append(state.dependency('gobject-introspection-1.0'))
self.gicompiler = self._find_tool(state, 'g-ir-compiler', for_machine=MachineChoice.HOST)
return self.giscanner, self.giscanner_extra, self.gicompiler

def _giscanner_version_compare(self, state: 'ModuleState', cmp: str) -> bool:
# Support for --version was introduced in g-i 1.58, but Ubuntu
# Bionic shipped 1.56.1. As all our version checks are greater
# than 1.58, we can just return False if get_version fails.
try:
giscanner, _, _ = self._get_gir_dep(state)
giscanner, _, _ = self._get_gi(state)
return mesonlib.version_compare(giscanner.get_version(), cmp)
except MesonException:
return False
Expand Down Expand Up @@ -998,6 +1003,8 @@ def _make_gir_target(
run_env.set('CFLAGS', [quote_arg(x) for x in env_flags], ' ')
run_env.merge(kwargs['env'])

giscanner, _, _ = self._get_gi(state)

# response file supported?
rspable = self._giscanner_version_compare(state, '>= 1.85.0')

Expand Down Expand Up @@ -1151,7 +1158,7 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut
if len(girtargets) > 1 and any(isinstance(el, 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)
giscanner, giscanner_extra, gicompiler = self._get_gi(state)

ns = kwargs['namespace']
nsversion = kwargs['nsversion']
Expand All @@ -1162,14 +1169,16 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut
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)
for extra in giscanner_extra:
depends.extend(extra.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]
deps += giscanner_extra # probably not necessary
deps += [state.dependency('glib-2.0'), state.dependency('gobject-2.0'), state.dependency('gmodule-2.0'), state.dependency('gio-2.0')]
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
Expand All @@ -1196,6 +1205,32 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut

scan_command: T.List[T.Union[str, Executable, 'ExternalProgram', 'OverrideProgram']] = [giscanner]
scan_command += ['--quiet']

if state.environment.is_cross_build() and state.environment.need_exe_wrapper() and giscanner.for_machine is MachineChoice.BUILD:
if not state.environment.has_exe_wrapper():
mlog.error('generate_gir requires exe_wrapper')

binary_wrapper = state.environment.get_exe_wrapper().get_command()
ldd = state.environment.lookup_binary_entry(MachineChoice.HOST, 'ldd')
if ldd is None:
ldd_wrapper = ['ldd']
else:
ldd_wrapper = ExternalProgram.from_bin_list(state.environment, MachineChoice.HOST, 'ldd').get_command()

WRAPPER_ARGS_REQUIRED_VERSION = ">=1.85.0"
if not self._giscanner_version_compare(state, WRAPPER_ARGS_REQUIRED_VERSION):
msg = ('Use of gnome.generate_gir during cross compilation requires'
f'g-ir-scanner {WRAPPER_ARGS_REQUIRED_VERSION}')
raise MesonException(msg)
else:
scan_command += ['--use-binary-wrapper', binary_wrapper[0]]
if len(binary_wrapper) > 1:
scan_command += ['--binary-wrapper-args-begin', *binary_wrapper[1:], '--binary-wrapper-args-end']

scan_command += ['--use-ldd-wrapper', ldd_wrapper[0]]
if len(ldd_wrapper) > 1:
scan_command += ['--ldd-wrapper-args-begin', *ldd_wrapper[1:], '--ldd-wrapper-args-end']

scan_command += ['--no-libtool']
scan_command += ['--namespace=' + ns, '--nsversion=' + nsversion]
scan_command += ['--warn-all']
Expand Down Expand Up @@ -1246,6 +1281,18 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut
# We have to cast here because mypy can't figure this out
T.cast('T.Dict[str, T.Any]', kwargs))

# The g-ir-compiler must match the host architecture. If we have
# found a g-ir-compiler for the build machine (due to it being
# specified in the cross file or meson just falling back to the
# system g-ir-compiler), check if its command begins with
# the command for exe_wrapper, in which case assume that it is
# actually compiled for the host architecture.
if state.environment.is_cross_build() and state.environment.need_exe_wrapper() and gicompiler.for_machine is MachineChoice.BUILD:
binary_wrapper = state.environment.get_exe_wrapper().get_command()
if gicompiler.get_command()[:len(binary_wrapper)] != binary_wrapper:
msg = 'Architecture of g-ir-compiler must match the one of the host machine'
raise MesonException(msg)

typelib_output = f'{ns}-{nsversion}.typelib'
typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
typelib_cmd += state.get_include_args(gir_inc_dirs, prefix='--includedir=')
Expand Down
Loading