From 9dde98c4299e6d180584e3c456a83ce5e85d289c Mon Sep 17 00:00:00 2001 From: taozuhong Date: Mon, 27 Apr 2026 19:56:12 +0800 Subject: [PATCH] Make meson crosss build simple --- cross/darwin-aarch64.ini | 23 ++++++++ cross/darwin-x86_64.ini | 23 ++++++++ cross/linux-aarch32.ini | 26 +++++++++ cross/linux-aarch64.ini | 26 +++++++++ cross/linux-x86.ini | 26 +++++++++ cross/linux-x86_64.ini | 26 +++++++++ cross/windows-aarch64.ini | 27 +++++++++ cross/windows-x86.ini | 27 +++++++++ cross/windows-x86_64.ini | 27 +++++++++ mesonbuild/cmdline.py | 16 +++++- mesonbuild/cross/__init__.py | 12 ++++ mesonbuild/cross/checker.py | 103 +++++++++++++++++++++++++++++++++++ mesonbuild/cross/registry.py | 90 ++++++++++++++++++++++++++++++ mesonbuild/msetup.py | 60 ++++++++++++++++++++ setup.py | 5 +- 15 files changed, 514 insertions(+), 3 deletions(-) create mode 100644 cross/darwin-aarch64.ini create mode 100644 cross/darwin-x86_64.ini create mode 100644 cross/linux-aarch32.ini create mode 100644 cross/linux-aarch64.ini create mode 100644 cross/linux-x86.ini create mode 100644 cross/linux-x86_64.ini create mode 100644 cross/windows-aarch64.ini create mode 100644 cross/windows-x86.ini create mode 100644 cross/windows-x86_64.ini create mode 100644 mesonbuild/cross/__init__.py create mode 100644 mesonbuild/cross/checker.py create mode 100644 mesonbuild/cross/registry.py diff --git a/cross/darwin-aarch64.ini b/cross/darwin-aarch64.ini new file mode 100644 index 000000000000..fbe0ac78fad2 --- /dev/null +++ b/cross/darwin-aarch64.ini @@ -0,0 +1,23 @@ +[binaries] +c = 'aarch64-apple-darwin20.4-clang' +cpp = 'aarch64-apple-darwin20.4-clang++' +ar = 'aarch64-apple-darwin20.4-ar' +strip = 'aarch64-apple-darwin20.4-strip' + +[host_machine] +system = 'darwin' +cpu_family = 'aarch64' +cpu = 'aarch64' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +aarch64-apple-darwin20.4-clang = '' +aarch64-apple-darwin20.4-clang++ = '' +aarch64-apple-darwin20.4-ar = '' +aarch64-apple-darwin20.4-strip = '' + +[required_packages] +osxcross = '' diff --git a/cross/darwin-x86_64.ini b/cross/darwin-x86_64.ini new file mode 100644 index 000000000000..7ec04929c0a9 --- /dev/null +++ b/cross/darwin-x86_64.ini @@ -0,0 +1,23 @@ +[binaries] +c = 'x86_64-apple-darwin20.4-clang' +cpp = 'x86_64-apple-darwin20.4-clang++' +ar = 'x86_64-apple-darwin20.4-ar' +strip = 'x86_64-apple-darwin20.4-strip' + +[host_machine] +system = 'darwin' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +x86_64-apple-darwin20.4-clang = '' +x86_64-apple-darwin20.4-clang++ = '' +x86_64-apple-darwin20.4-ar = '' +x86_64-apple-darwin20.4-strip = '' + +[required_packages] +osxcross = '' diff --git a/cross/linux-aarch32.ini b/cross/linux-aarch32.ini new file mode 100644 index 000000000000..95d661338e1d --- /dev/null +++ b/cross/linux-aarch32.ini @@ -0,0 +1,26 @@ +[binaries] +c = 'arm-linux-gnueabihf-gcc' +cpp = 'arm-linux-gnueabihf-g++' +ar = 'arm-linux-gnueabihf-ar' +strip = 'arm-linux-gnueabihf-strip' +pkg-config = 'arm-linux-gnueabihf-pkg-config' + +[host_machine] +system = 'linux' +cpu_family = 'arm' +cpu = 'armv7' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +arm-linux-gnueabihf-gcc = '' +arm-linux-gnueabihf-g++ = '' +arm-linux-gnueabihf-ar = '' +arm-linux-gnueabihf-strip = '' +arm-linux-gnueabihf-pkg-config = '' + +[required_packages] +g++-arm-linux-gnueabihf = '' +binutils-arm-linux-gnueabihf = '' diff --git a/cross/linux-aarch64.ini b/cross/linux-aarch64.ini new file mode 100644 index 000000000000..1560148f1456 --- /dev/null +++ b/cross/linux-aarch64.ini @@ -0,0 +1,26 @@ +[binaries] +c = 'aarch64-linux-gnu-gcc' +cpp = 'aarch64-linux-gnu-g++' +ar = 'aarch64-linux-gnu-ar' +strip = 'aarch64-linux-gnu-strip' +pkg-config = 'aarch64-linux-gnu-pkg-config' + +[host_machine] +system = 'linux' +cpu_family = 'aarch64' +cpu = 'aarch64' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +aarch64-linux-gnu-gcc = '' +aarch64-linux-gnu-g++ = '' +aarch64-linux-gnu-ar = '' +aarch64-linux-gnu-strip = '' +aarch64-linux-gnu-pkg-config = '' + +[required_packages] +g++-aarch64-linux-gnu = '' +binutils-aarch64-linux-gnu = '' diff --git a/cross/linux-x86.ini b/cross/linux-x86.ini new file mode 100644 index 000000000000..1f67746bfab7 --- /dev/null +++ b/cross/linux-x86.ini @@ -0,0 +1,26 @@ +[binaries] +c = 'i686-linux-gnu-gcc' +cpp = 'i686-linux-gnu-g++' +ar = 'i686-linux-gnu-ar' +strip = 'i686-linux-gnu-strip' +pkg-config = 'i686-linux-gnu-pkg-config' + +[host_machine] +system = 'linux' +cpu_family = 'x86' +cpu = 'i686' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +i686-linux-gnu-gcc = '' +i686-linux-gnu-g++ = '' +i686-linux-gnu-ar = '' +i686-linux-gnu-strip = '' +i686-linux-gnu-pkg-config = '' + +[required_packages] +g++-i686-linux-gnu = '' +binutils-i686-linux-gnu = '' diff --git a/cross/linux-x86_64.ini b/cross/linux-x86_64.ini new file mode 100644 index 000000000000..1fb7eda83014 --- /dev/null +++ b/cross/linux-x86_64.ini @@ -0,0 +1,26 @@ +[binaries] +c = 'x86_64-linux-gnu-gcc' +cpp = 'x86_64-linux-gnu-g++' +ar = 'x86_64-linux-gnu-ar' +strip = 'x86_64-linux-gnu-strip' +pkg-config = 'x86_64-linux-gnu-pkg-config' + +[host_machine] +system = 'linux' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +x86_64-linux-gnu-gcc = '' +x86_64-linux-gnu-g++ = '' +x86_64-linux-gnu-ar = '' +x86_64-linux-gnu-strip = '' +x86_64-linux-gnu-pkg-config = '' + +[required_packages] +g++-x86-64-linux-gnu = '' +binutils-x86-64-linux-gnu = '' diff --git a/cross/windows-aarch64.ini b/cross/windows-aarch64.ini new file mode 100644 index 000000000000..30690118f9f4 --- /dev/null +++ b/cross/windows-aarch64.ini @@ -0,0 +1,27 @@ +[binaries] +c = 'aarch64-w64-mingw32-gcc' +cpp = 'aarch64-w64-mingw32-g++' +ar = 'aarch64-w64-mingw32-ar' +strip = 'aarch64-w64-mingw32-strip' +pkg-config = 'aarch64-w64-mingw32-pkg-config' +windres = 'aarch64-w64-mingw32-windres' + +[host_machine] +system = 'windows' +cpu_family = 'aarch64' +cpu = 'aarch64' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +aarch64-w64-mingw32-gcc = '' +aarch64-w64-mingw32-g++ = '' +aarch64-w64-mingw32-ar = '' +aarch64-w64-mingw32-strip = '' +aarch64-w64-mingw32-pkg-config = '' +aarch64-w64-mingw32-windres = '' + +[required_packages] +mingw-w64-aarch64-dev = '' diff --git a/cross/windows-x86.ini b/cross/windows-x86.ini new file mode 100644 index 000000000000..80fef453fd68 --- /dev/null +++ b/cross/windows-x86.ini @@ -0,0 +1,27 @@ +[binaries] +c = 'i686-w64-mingw32-gcc' +cpp = 'i686-w64-mingw32-g++' +ar = 'i686-w64-mingw32-ar' +strip = 'i686-w64-mingw32-strip' +pkg-config = 'i686-w64-mingw32-pkg-config' +windres = 'i686-w64-mingw32-windres' + +[host_machine] +system = 'windows' +cpu_family = 'x86' +cpu = 'i686' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +i686-w64-mingw32-gcc = '' +i686-w64-mingw32-g++ = '' +i686-w64-mingw32-ar = '' +i686-w64-mingw32-strip = '' +i686-w64-mingw32-pkg-config = '' +i686-w64-mingw32-windres = '' + +[required_packages] +mingw-w64-i686-dev = '' diff --git a/cross/windows-x86_64.ini b/cross/windows-x86_64.ini new file mode 100644 index 000000000000..a8b7aba2d901 --- /dev/null +++ b/cross/windows-x86_64.ini @@ -0,0 +1,27 @@ +[binaries] +c = 'x86_64-w64-mingw32-gcc' +cpp = 'x86_64-w64-mingw32-g++' +ar = 'x86_64-w64-mingw32-ar' +strip = 'x86_64-w64-mingw32-strip' +pkg-config = 'x86_64-w64-mingw32-pkg-config' +windres = 'x86_64-w64-mingw32-windres' + +[host_machine] +system = 'windows' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[properties] +needs_exe_wrapper = true + +[required_binaries] +x86_64-w64-mingw32-gcc = '' +x86_64-w64-mingw32-g++ = '' +x86_64-w64-mingw32-ar = '' +x86_64-w64-mingw32-strip = '' +x86_64-w64-mingw32-pkg-config = '' +x86_64-w64-mingw32-windres = '' + +[required_packages] +mingw-w64-x86-64-dev = '' diff --git a/mesonbuild/cmdline.py b/mesonbuild/cmdline.py index 2de75ae07d98..ba68cb0a68d6 100644 --- a/mesonbuild/cmdline.py +++ b/mesonbuild/cmdline.py @@ -35,6 +35,8 @@ class SharedCMDOptions(Protocol): d_keys: T.Set[OptionKey] cross_file: T.List[str] native_file: T.List[str] + cross_os: T.Optional[str] + cross_arch: T.Optional[str] class CmdLineFileParser(configparser.ConfigParser): @@ -77,16 +79,24 @@ def read_cmd_line_file(build_dir: str, options: SharedCMDOptions) -> None: # This will be a string in the form: "['first', 'second', ...]", use # literal_eval to get it into the list of strings. options.native_file = ast.literal_eval(properties.get('native_file', '[]')) + if options.cross_os is None: + options.cross_os = properties.get('cross_os') + if options.cross_arch is None: + options.cross_arch = properties.get('cross_arch') def write_cmd_line_file(build_dir: str, options: SharedCMDOptions) -> None: filename = get_cmd_line_file(build_dir) config = CmdLineFileParser() - properties: T.Dict[str, T.List[str]] = {} + properties: T.Dict[str, T.Union[str, T.List[str]]] = {} if options.cross_file: properties['cross_file'] = options.cross_file if options.native_file: properties['native_file'] = options.native_file + if options.cross_os: + properties['cross_os'] = options.cross_os + if options.cross_arch: + properties['cross_arch'] = options.cross_arch config['options'] = {str(k): str(v) for k, v in options.cmd_line_options.items()} config['properties'] = {k: repr(v) for k, v in properties.items()} @@ -118,6 +128,10 @@ def format_cmd_line_options(options: SharedCMDOptions) -> str: cmdline += [f'--cross-file={f}' for f in options.cross_file] if options.native_file: cmdline += [f'--native-file={f}' for f in options.native_file] + if options.cross_os: + cmdline += [f'--cross-os={options.cross_os}'] + if options.cross_arch: + cmdline += [f'--cross-arch={options.cross_arch}'] return ' '.join([shlex.quote(x) for x in cmdline]) diff --git a/mesonbuild/cross/__init__.py b/mesonbuild/cross/__init__.py new file mode 100644 index 000000000000..d4c725e0f82f --- /dev/null +++ b/mesonbuild/cross/__init__.py @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2025 The Meson development team + +from .registry import CrossConfigRegistry, CrossConfigNotFoundError +from .checker import DependencyChecker, DependencyCheckResult + +__all__ = [ + 'CrossConfigRegistry', + 'CrossConfigNotFoundError', + 'DependencyChecker', + 'DependencyCheckResult', +] diff --git a/mesonbuild/cross/checker.py b/mesonbuild/cross/checker.py new file mode 100644 index 000000000000..5d03d227754f --- /dev/null +++ b/mesonbuild/cross/checker.py @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2025 The Meson development team + +from __future__ import annotations + +import dataclasses +import shutil +import subprocess +import sys +import typing as T + + +@dataclasses.dataclass +class DependencyCheckResult: + """Result of a cross-compilation dependency pre-flight check.""" + all_ok: bool = True + missing_binaries: T.Dict[str, str] = dataclasses.field(default_factory=dict) + missing_packages: T.Dict[str, str] = dataclasses.field(default_factory=dict) + + def add_missing_binary(self, name: str, reason: str) -> None: + self.missing_binaries[name] = reason + self.all_ok = False + + def add_missing_package(self, name: str, reason: str) -> None: + self.missing_packages[name] = reason + self.all_ok = False + + +class DependencyChecker: + """Validates that cross-compilation prerequisites are installed. + + Reads ``[required_binaries]`` and ``[required_packages]`` sections from a + parsed machine-file sections dictionary and checks that each is available. + """ + + def __init__(self, sections: T.Dict[str, T.Dict[str, T.Any]]) -> None: + self._required_binaries: T.Dict[str, str] = {} + self._required_packages: T.Dict[str, str] = {} + + raw_binaries = sections.get('required_binaries', {}) + for k, v in raw_binaries.items(): + self._required_binaries[str(k)] = str(v) if v is not None else '' + + raw_packages = sections.get('required_packages', {}) + for k, v in raw_packages.items(): + self._required_packages[str(k)] = str(v) if v is not None else '' + + def check(self) -> DependencyCheckResult: + """Run all dependency checks, collecting every failure.""" + result = DependencyCheckResult() + + for binary, _version in self._required_binaries.items(): + found = shutil.which(binary) + if found is None: + result.add_missing_binary(binary, 'not found on PATH') + + for pkg, _version in self._required_packages.items(): + if not self._check_system_package(pkg): + result.add_missing_package(pkg, self._pkg_install_hint(pkg)) + + return result + + @staticmethod + def _check_system_package(pkg_name: str) -> bool: + if not sys.platform.startswith('linux'): + return True # can't check on non-Linux; don't block + try: + subprocess.run( + ['dpkg-query', '-W', '-f', '${Status}', pkg_name], + capture_output=True, text=True, check=True) + return True + except (subprocess.CalledProcessError, FileNotFoundError): + pass + try: + subprocess.run( + ['rpm', '-q', pkg_name], + capture_output=True, text=True, check=True) + return True + except (subprocess.CalledProcessError, FileNotFoundError): + pass + return False + + @staticmethod + def _pkg_install_hint(pkg_name: str) -> str: + if sys.platform.startswith('linux'): + return f'Try: apt install {pkg_name} or dnf install {pkg_name}' + return 'Please install this package manually' + + @staticmethod + def format_report(result: DependencyCheckResult) -> str: + """Build a human-readable report from a check result.""" + lines: T.List[str] = [] + if result.missing_binaries: + lines.append('Missing binaries (not found on PATH):') + for name, reason in sorted(result.missing_binaries.items()): + lines.append(f' - {name}: {reason}') + if result.missing_packages: + lines.append('Missing system packages:') + for name, reason in sorted(result.missing_packages.items()): + lines.append(f' - {name}: {reason}') + if not lines: + lines.append('All cross-compilation dependencies are satisfied.') + return '\n'.join(lines) diff --git a/mesonbuild/cross/registry.py b/mesonbuild/cross/registry.py new file mode 100644 index 000000000000..4444c66249cf --- /dev/null +++ b/mesonbuild/cross/registry.py @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2025 The Meson development team + +from __future__ import annotations + +import os +import sys +from pathlib import Path +import typing as T + +from ..mesonlib import MesonException + + +class CrossConfigNotFoundError(MesonException): + """Raised when no cross-config file matches the requested (os, arch) pair.""" + + +def _xdg_cross_dirs() -> T.List[Path]: + """Return XDG data directories with ``meson/cross`` appended. + + Mirrors the search logic in ``coredata.__load_config_files``. + """ + if sys.platform == 'win32': + return [] + data_home = os.environ.get('XDG_DATA_HOME', os.path.expanduser('~/.local/share')) + data_dirs = os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share') + return [Path(data_home) / 'meson' / 'cross'] + [ + Path(d) / 'meson' / 'cross' for d in data_dirs.split(':') + ] + + +class CrossConfigRegistry: + """Registry of built-in and user-override cross-compilation configuration files. + + Search order for a given ``(os, arch)`` pair: + 1. ``~/.meson/cross/-.ini`` (user override) + 2. ``/cross/-.ini`` (built-in, source tree) + 3. ``$XDG_DATA_DIRS/meson/cross/-.ini`` (system install) + """ + + def __init__(self) -> None: + self._user_dir = Path.home() / '.meson' / 'cross' + # Source tree: the top-level cross/ directory (relative to this module) + self._sourcedir_cross = Path(__file__).parent.parent.parent / 'cross' + self._cache: T.Dict[T.Tuple[str, str], Path] = {} + + def _search_dirs(self) -> T.List[Path]: + """Return all directories to search, in priority order.""" + dirs = [self._user_dir, self._sourcedir_cross] + dirs += _xdg_cross_dirs() + # Also cover pip/virtualenv installs where data_files lands under sys.prefix + dirs.append(Path(sys.prefix) / 'share' / 'meson' / 'cross') + return dirs + + def resolve(self, os_name: str, arch: str) -> Path: + """Resolve a cross-config file for the given target. + + :returns: Absolute path to the ``.ini`` file. + :raises CrossConfigNotFoundError: if no config matches the pair. + """ + key = (os_name, arch) + if key in self._cache: + return self._cache[key] + + filename = f'{os_name}-{arch}.ini' + + for base_dir in self._search_dirs(): + if not base_dir.is_dir(): + continue + candidate = base_dir / filename + if candidate.is_file(): + self._cache[key] = candidate + return candidate + + known = self.list_available() + raise CrossConfigNotFoundError( + f'No cross-compilation configuration found for OS={os_name}, ARCH={arch}.\n' + f'Available built-in targets: {", ".join(known) if known else "(none)"}\n' + f'You can create ~/.meson/cross/{filename} to define a custom cross-compilation config.' + ) + + def list_available(self) -> T.List[str]: + """Return sorted list of available target names (e.g. ``'linux-aarch32'``).""" + names: T.List[str] = [] + for d in self._search_dirs(): + if d.is_dir(): + for f in d.iterdir(): + if f.suffix == '.ini': + names.append(f.stem) + return sorted(set(names)) diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index df06245a394c..5715a5cb1baa 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -10,6 +10,8 @@ import typing as T from . import build, cmdline, coredata, environment, interpreter, mesonlib, mintro, mlog +from . import machinefile +from .cross import CrossConfigRegistry, CrossConfigNotFoundError, DependencyChecker from .dependencies import Dependency from .mesonlib import MesonException from .interpreterbase import ObjectHolder @@ -30,6 +32,8 @@ class CMDOptions(SharedCMDOptions, Protocol): builddir: str sourcedir: str pager: bool + cross_os: T.Optional[str] + cross_arch: T.Optional[str] git_ignore_file = '''# This file is autogenerated by Meson. If you change or delete it, it won't be recreated. * @@ -53,6 +57,16 @@ def add_arguments(parser: argparse.ArgumentParser) -> None: default=[], action='append', help='File describing cross compilation environment.') + parser.add_argument('--cross-os', + default=None, + help='Cross-compile target OS (e.g. linux, windows, darwin). ' + 'Used together with --cross-arch to resolve a built-in ' + 'cross-compilation config.') + parser.add_argument('--cross-arch', + default=None, + help='Cross-compile target CPU architecture (e.g. armhf, aarch64, x86_64). ' + 'Used together with --cross-os to resolve a built-in ' + 'cross-compilation config.') parser.add_argument('-v', '--version', action='version', version=coredata.version) parser.add_argument('--profile-self', action='store_true', dest='profile', @@ -385,6 +399,49 @@ def run_genvslite_setup(options: CMDOptions) -> None: app = MesonApp(options) app.generate(capture=False, vslite_ctx=vslite_ctx) +def _resolve_cross_config(options: CMDOptions) -> None: + """Resolve --cross-os and --cross-arch to a cross file path. + + Looks up the matching built-in (or user-override) cross-compilation + configuration, checks that required dependencies are installed, and + appends the resolved config path to ``options.cross_file`` so the + standard cross-compilation pipeline can proceed unchanged. + """ + if options.cross_os is None or options.cross_arch is None: + raise MesonException( + 'Both --cross-os and --cross-arch must be specified together.\n' + 'Example: meson setup --cross-os=linux --cross-arch=armhf builddir') + + registry = CrossConfigRegistry() + try: + config_path = registry.resolve(options.cross_os, options.cross_arch) + except CrossConfigNotFoundError as e: + raise MesonException(str(e)) + + mlog.log('Using cross-compilation config:', mlog.bold(str(config_path))) + + sections = machinefile.parse_machine_files([str(config_path)], os.getcwd()) + + checker = DependencyChecker(sections) + result = checker.check() + if not result.all_ok: + mlog.log('') + mlog.log(mlog.red('ERROR:'), 'Missing cross-compilation dependencies:') + mlog.log(DependencyChecker.format_report(result)) + mlog.log('') + mlog.log('Please install the missing dependencies and re-run meson setup.') + raise MesonException('Cross-compilation dependency check failed.') + + mlog.log('All cross-compilation dependencies satisfied.') + + if options.cross_file: + mlog.warning( + 'Both --cross-file and --cross-os/--cross-arch specified. ' + 'The resolved config will be appended to the cross file list.', + fatal=False) + + options.cross_file.append(str(config_path)) + def run(options: T.Union[CMDOptions, T.List[str]]) -> int: if isinstance(options, list): parser = argparse.ArgumentParser() @@ -392,6 +449,9 @@ def run(options: T.Union[CMDOptions, T.List[str]]) -> int: options = T.cast('CMDOptions', parser.parse_args(options)) cmdline.parse_cmd_line_options(options) + if options.cross_os is not None or options.cross_arch is not None: + _resolve_cross_config(options) + # Msetup doesn't actually use this option, but we pass msetup options to # mconf, and it does. We won't actually hit the path that uses it, but don't # lie diff --git a/setup.py b/setup.py index 4b5cb6bf349a..76ea44d8a315 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ # Copyright 2016 The Meson development team -import os, sys +import glob, os, sys if sys.version_info < (3, 10): raise SystemExit('ERROR: Tried to install Meson with an unsupported Python version: \n{}' @@ -29,6 +29,7 @@ if sys.platform != 'win32': # Only useful on UNIX-like systems data_files = [('share/man/man1', ['man/meson.1']), - ('share/polkit-1/actions', ['data/com.mesonbuild.install.policy'])] + ('share/polkit-1/actions', ['data/com.mesonbuild.install.policy']), + ('share/meson/cross', sorted(glob.glob('cross/*.ini')))] setup(data_files=data_files,**scm_args)