Skip to content

Commit 13c6748

Browse files
committed
ENH: support setuptools-style macOS cross compilation via ARCHFLAGS
1 parent 67a5f7f commit 13c6748

File tree

1 file changed

+37
-5
lines changed

1 file changed

+37
-5
lines changed

mesonpy/__init__.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ def build(self, directory: Path) -> pathlib.Path:
543543

544544

545545
MesonArgsKeys = Literal['dist', 'setup', 'compile', 'install']
546-
MesonArgs = Mapping[MesonArgsKeys, Collection[str]]
546+
MesonArgs = Mapping[MesonArgsKeys, List[str]]
547547

548548

549549
class Project():
@@ -554,7 +554,7 @@ class Project():
554554
]
555555
_metadata: Optional[pyproject_metadata.StandardMetadata]
556556

557-
def __init__(
557+
def __init__( # noqa: C901
558558
self,
559559
source_dir: Path,
560560
working_dir: Path,
@@ -566,13 +566,41 @@ def __init__(
566566
self._build_dir = pathlib.Path(build_dir).absolute() if build_dir else (self._working_dir / 'build')
567567
self._install_dir = self._working_dir / 'install'
568568
self._meson_native_file = self._source_dir / '.mesonpy-native-file.ini'
569+
self._meson_cross_file = self._source_dir / '.mesonpy-cross-file.ini'
570+
self._meson_args: MesonArgs = collections.defaultdict(list)
569571
self._env = os.environ.copy()
570572

571573
# prepare environment
572574
ninja_path = _env_ninja_command()
573575
if ninja_path is not None:
574576
self._env.setdefault('NINJA', str(ninja_path))
575577

578+
# setuptools-like ARCHFLAGS environment variable support
579+
if sysconfig.get_platform().startswith('macosx-'):
580+
archflags = self._env.get('ARCHFLAGS')
581+
if archflags is not None:
582+
arch, *other = filter(None, (x.strip() for x in archflags.split('-arch')))
583+
if other:
584+
raise ConfigError(f'multi-architecture builds are not supported but $ARCHFLAGS={archflags!r}')
585+
macver, _, nativearch = platform.mac_ver()
586+
if arch != nativearch:
587+
x = self._env.setdefault('_PYTHON_HOST_PLATFORM', f'macosx-{macver}-{arch}')
588+
if not x.endswith(arch):
589+
raise ConfigError(f'$ARCHFLAGS={archflags!r} and $_PYTHON_HOST_PLATFORM={x!r} do not agree')
590+
family = 'aarch64' if arch == 'arm64' else arch
591+
cross_file_data = textwrap.dedent(f'''
592+
[binaries]
593+
c = ['cc', '-arch', {arch!r}]
594+
cpp = ['cpp', '-arch', {arch!r}]
595+
[host_machine]
596+
system = 'Darwin'
597+
cpu = {arch!r}
598+
cpu_family = {family!r}
599+
endian = 'little'
600+
''')
601+
self._meson_cross_file.write_text(cross_file_data)
602+
self._meson_args['setup'].extend(('--cross-file', os.fspath(self._meson_cross_file)))
603+
576604
# load config -- PEP 621 support is optional
577605
self._config = tomllib.loads(self._source_dir.joinpath('pyproject.toml').read_text())
578606
self._pep621 = 'project' in self._config
@@ -594,16 +622,20 @@ def __init__(
594622
self._validate_metadata()
595623

596624
# load meson args
597-
self._meson_args = collections.defaultdict(tuple, meson_args or {})
598625
for key in self._get_config_key('args'):
599-
args_from_config = tuple(self._get_config_key(f'args.{key}'))
600-
self._meson_args[key] = args_from_config + tuple(self._meson_args[key])
626+
self._meson_args[key].extend(self._get_config_key(f'args.{key}'))
601627
# XXX: We should validate the user args to make sure they don't conflict with ours.
602628

603629
self._check_for_unknown_config_keys({
604630
'args': typing_get_args(MesonArgsKeys),
605631
})
606632

633+
# meson arguments from the command line take precedence over
634+
# arguments from the configuration file thus are added later
635+
if meson_args:
636+
for key, value in meson_args.items():
637+
self._meson_args[key].extend(value)
638+
607639
# make sure the build dir exists
608640
self._build_dir.mkdir(exist_ok=True)
609641
self._install_dir.mkdir(exist_ok=True)

0 commit comments

Comments
 (0)