Skip to content

Add support for targeting Android#824

Open
mhsmith wants to merge 1 commit intomesonbuild:mainfrom
mhsmith:android
Open

Add support for targeting Android#824
mhsmith wants to merge 1 commit intomesonbuild:mainfrom
mhsmith:android

Conversation

@mhsmith
Copy link

@mhsmith mhsmith commented Dec 10, 2025

Using the same approach as on iOS.

This PR branch is temporarily used by several other PRs: see the cross-references below.

@rgommers rgommers added the enhancement New feature or request label Dec 10, 2025
@rgommers
Copy link
Contributor

Thanks @mhsmith. Same approach as for iOS seems fine indeed. I added "Closes gh-810" to the PR description.

@mhsmith
Copy link
Author

mhsmith commented Jan 31, 2026

@rgommers: This PR is ready for review. Compared to the iOS PR, this one is a bit simpler:

  • No updates were required to Meson itself.
  • No special handling was required for Android versions or wheel tags, since this is all done by cibuildwheel.

Copy link
Contributor

@rgommers rgommers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mhsmith. The main question I have now is: it looks like you're assuming that only cibuildwheel will be supported, and not regular cross compilation to Android. Is that correct? If so, I'm not sure that's right - and the iOS support doesn't do that as far as I can tell (or it's more hidden and missing code comments?).

Other questions that came up for me, like what platforms Android supports (e.g., armv7) and whether that's supported when using cpu_family = {platform.machine()!r} kinda depend on that first question.

@mhsmith
Copy link
Author

mhsmith commented Feb 1, 2026

it looks like you're assuming that only cibuildwheel will be supported, and not regular cross compilation to Android

That's a good point: Android packages could be native-compiled in an environment like Termux. I've changed the code to only use cross-compilation mode when it detects it's running within cibuildwheel.

As far as I know, there's no native compilation option on iOS, because the platform is too restrictive, e.g. apps cannot create subprocesses.

Other questions that came up for me, like what platforms Android supports (e.g., armv7) and whether that's supported when using cpu_family = {platform.machine()!r}

Officially Python only supports Android on aarch64 and x86_64. However, it's used unofficially on other architectures, so I've added coverage for all the known values of platform.machine that Android can return.

@mhsmith mhsmith requested a review from rgommers February 1, 2026 17:05
@eli-schwartz
Copy link
Member

That's a good point: Android packages could be native-compiled in an environment like Termux. I've changed the code to only use cross-compilation mode when it detects it's running within cibuildwheel.

Anecdotally, Termux for me shows python 3.12 with a platform value of "Linux". :)

@mhsmith
Copy link
Author

mhsmith commented Feb 1, 2026

Yes, that was changed in Python 3.13 when we added official Android support. cibuildwheel will only support Android on Python 3.13 or later, so the cross file should use the new value.

@rgommers
Copy link
Contributor

rgommers commented Feb 2, 2026

We get the occasional Termux-related bug report in NumPy, so that does appear to be used indeed.

The approach you took now looks better to me. CIBW_HOST_TRIPLET doesn't seem to be a public environment variable for cibuildwheel though (or is it just missing from the docs?), so it might be safer to pick a variable that is public?

@mhsmith
Copy link
Author

mhsmith commented Feb 4, 2026

I'm not aware of any public way to detect that a build is running within cibuildwheel. The environment variables in their documentation are all used as configuration inputs to cibuildwheel, rather than outputs that you can rely on being set within the build.

So I've changed it to use sys.cross_compiling instead, which has the advantage of not depending on any particular build tool.

@rgommers
Copy link
Contributor

rgommers commented Feb 6, 2026

Thanks for the update.

So I've changed it to use sys.cross_compiling instead, which has the advantage of not depending on any particular build tool.

It does depend on tools, right? I guess all we care about here is that cibuildwheel sets that. Proper cross-compiling (i.e., provide a cross file, not with hacks like crossenv) will not have this set, but as long as we document that it's specific to cibuildwheel and crossenv I can live with this code, given that there indeed doesn't appear to be an officially supported way to special-case cibuildwheel.

@mhsmith
Copy link
Author

mhsmith commented Feb 8, 2026

Python doesn't really provide any "proper cross-compiling" mechanism, so the crossenv-like approach is the only feasible option for cross-compiling Android and iOS wheels at the moment.

as long as we document that it's specific to cibuildwheel and crossenv I can live with this code

I've mentioned that in the comment on line 749.

@rgommers
Copy link
Contributor

rgommers commented Feb 8, 2026

Thanks @mhsmith. For context: Python itself doesn't, and probably won't for at least a couple more years, but both Meson and CMake have solid cross-compilation support, and with Meson cross files + PEP 739 (build-details.json) cross compilation can start to look pretty clean. E.g., see this branch for scipy, it comes down to setting up the build and host envs, and then:

python -m build -wnx -Csetup-args=--cross-file=$PWD/ci/cross_aarch64.ini -Csetup-args=-Dpython.build_config=$HOST_ENV/lib/python3.14/build-details.json

Support in Meson for PEP 739 has landed, and support in meson-python will follow (hopefully soon). All that "support in Python" should then mean is "how do we point at the target interpreter (i.e., $HOST_ENV/lib/python3.14/build-details.json) in a more ergonomic fashion?".

tl;dr we should not build in implicit assumptions around crossenv anywhere in the ecosystem, because that's a pretty bad pile of hacks under the hood, and not supportable properly long-term, or even today by distros.

Comment on lines +748 to +750
# with cibuildwheel), in which case we should generate a cross file.
# sys.cross_compiling isn't an official Python API, but it originated from
# crossenv and has been followed by other cross-compiling tools.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hence I suggest to change the comment along these lines:

Suggested change
# with cibuildwheel), in which case we should generate a cross file.
# sys.cross_compiling isn't an official Python API, but it originated from
# crossenv and has been followed by other cross-compiling tools.
Cross compilation can be done the regular Meson way with separate build and host envs,
or with `cibuildwheel` which is `crossenv`-based. Here we try to detect whether
cibuildwheel/crossenv are used, through the `sys.cross_compiling` variable which they
define, and we synthesize a cross file in that case to make that work out of the box.

I think the idea and code are fine.

Copy link
Member

@dnicolodi dnicolodi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand what this PR implements. The commit message states that this implements support for Android. However, it seems to implement support for cross-compiling for Android. I think native compilation for Android works already as I don't have evidence of the contrary and this PR does not affect native compilation.

Furthermore, this PR seems to only address the case of a cross compilation environment setup by cibuildwheel. However, the code and the comments therein seem to indicate that this is somehow more generic.

I think that supporting cibuildwheel covers an important use case, thus this PR is good to have. On the other hand, it seems that we are designing support for new systems with the same ugly hacks that were used in the past to work around limitations it the build tools. Concretely, i don't understand why we need to rely on sys.cross_compiling. If this is designed to support only cibuildwheel I am sure we can use some other indicator to detect the cross compilation environment, especially if we already rely on environment variables to setup the compilation environment.

# sys.cross_compiling isn't an official Python API, but it originated from
# crossenv and has been followed by other cross-compiling tools.
elif (
sysconfig.get_platform().startswith('android-')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not simply

Suggested change
sysconfig.get_platform().startswith('android-')
sys.platform == 'android'

?

Comment on lines +761 to +762
# Binaries are controlled by environment variables, so they don't need
# to be repeated here.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is any value in adding this comment to the generated file.

Comment on lines +756 to +758
cpu_family = (
'arm' if cpu.startswith('arm') else 'x86' if cpu.endswith('86') else cpu
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cpu_family = (
'arm' if cpu.startswith('arm') else 'x86' if cpu.endswith('86') else cpu
)
cpu_family = 'arm' if cpu.startswith('arm') else 'x86' if cpu.endswith('86') else cpu

This is ugly, but please don't use the black code uglifier to make it uglier.

Comment on lines +751 to +754
elif (
sysconfig.get_platform().startswith('android-')
and getattr(sys, 'cross_compiling', False)
):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
elif (
sysconfig.get_platform().startswith('android-')
and getattr(sys, 'cross_compiling', False)
):
elif sys.platform == 'android' and getattr(sys, 'cross_compiling', False):

Please don't use the black code uglifier.

Comment on lines +772 to +774
# cibuildwheel's cross virtual environment will make Meson believe it's
# running on Android when it's actually running on Linux or macOS.
needs_exe_wrapper = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get how the comment (which I don't think should be in the generated file) goes with the implemented setting. How does cibuildwheel makes Meson believe it is running on Android? And why does it do so? It is clearly not the case. Also, what it the exe wrapper that is needed? This seems incomplete at best.

monkeypatch.setattr(sysconfig, 'get_platform', Mock(return_value='android-24'))
if cross:
monkeypatch.setattr(sys, 'cross_compiling', True, raising=False)
monkeypatch.setenv('STRIP', '/path/to/strip')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is setting this environment variable needed?

@mhsmith
Copy link
Author

mhsmith commented Feb 8, 2026

Thanks for the comments. I have some business travel and vacation coming up, so it'll probably take me a couple of weeks to reply.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Add support for building Android wheels

4 participants