Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork11.9k
BLD: cross-compilation for android using cibuildwheel#29770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Conversation
- pyproject: remove unused android test package- cibw_before_build_android.sh: remove redundant code- remove android.meson.cross: cross files are dynamically generated via cibw_before_build_android.sh
andyfaff commentedSep 20, 2025
A discussion is needed before we add wheel support for the Android platform. These discussions take place onnumpy-discussion@scipy.org, as well as the regular online meetings (advertised on the mailing list). Whilst Android is obviously quite popular we need to know that finite resources (developer time, CI time) is going spent effectively. i.e. we need to know that demand will be there. Probably the first step would be to add a CI entry, rather than distributing a wheel. |
andyfaff commentedSep 20, 2025
Ok, so the original issue said all of that and more. We'd probably be looking for a CI entry for regular test runs, not building a wheel. |
| # Override system library detection for Android - math functions are in libc | ||
| c_args = ['-DHAVE_SIN=1', '-DHAVE_COS=1', '-DHAVE_TAN=1', '-DHAVE_SINH=1', '-DHAVE_COSH=1', '-DHAVE_TANH=1', '-DHAVE_ASIN=1', '-DHAVE_ACOS=1', '-DHAVE_ATAN=1', '-DHAVE_ATAN2=1', '-DHAVE_EXP=1', '-DHAVE_LOG=1', '-DHAVE_LOG10=1', '-DHAVE_SQRT=1', '-DHAVE_FLOOR=1', '-DHAVE_CEIL=1', '-DHAVE_FABS=1', '-DHAVE_POW=1', '-DHAVE_FMOD=1', '-DHAVE_LDEXP=1', '-DHAVE_FREXP=1', '-DHAVE_MODF=1', '-DHAVE_COPYSIGN=1', '-DHAVE_FINITE=1', '-DHAVE_ISINF=1', '-DHAVE_ISNAN=1', '-DHAVE_ISFINITE=1', '-DHAVE_EXPM1=1', '-DHAVE_LOG1P=1', '-DHAVE_ASINH=1', '-DHAVE_ACOSH=1', '-DHAVE_ATANH=1', '-DHAVE_RINT=1', '-DHAVE_TRUNC=1', '-DHAVE_EXP2=1', '-DHAVE_LOG2=1', '-DHAVE_HYPOT=1', '-DHAVE_CBRT=1', '-DHAVE_NEXTAFTER=1', '-DHAVE_CSIN=1', '-DHAVE_CCOS=1', '-DHAVE_CTAN=1', '-DHAVE_CSINH=1', '-DHAVE_CCOSH=1', '-DHAVE_CTANH=1', '-DHAVE_CASIN=1', '-DHAVE_CACOS=1', '-DHAVE_CATAN=1', '-DHAVE_CASINH=1', '-DHAVE_CACOSH=1', '-DHAVE_CATANH=1', '-DHAVE_CEXP=1', '-DHAVE_CLOG=1', '-DHAVE_CPOW=1', '-DHAVE_CSQRT=1', '-DHAVE_CABS=1', '-DHAVE_CARG=1', '-DHAVE_CIMAG=1', '-DHAVE_CREAL=1', '-DHAVE_CONJ=1', '-DHAVE_STRTOLL=1', '-DHAVE_STRTOULL=1', '-DHAVE_STRTOLD=1'] | ||
| cpp_args = ['-DHAVE_SIN=1', '-DHAVE_COS=1', '-DHAVE_TAN=1', '-DHAVE_SINH=1', '-DHAVE_COSH=1', '-DHAVE_TANH=1', '-DHAVE_ASIN=1', '-DHAVE_ACOS=1', '-DHAVE_ATAN=1', '-DHAVE_ATAN2=1', '-DHAVE_EXP=1', '-DHAVE_LOG=1', '-DHAVE_LOG10=1', '-DHAVE_SQRT=1', '-DHAVE_FLOOR=1', '-DHAVE_CEIL=1', '-DHAVE_FABS=1', '-DHAVE_POW=1', '-DHAVE_FMOD=1', '-DHAVE_LDEXP=1', '-DHAVE_FREXP=1', '-DHAVE_MODF=1', '-DHAVE_COPYSIGN=1', '-DHAVE_FINITE=1', '-DHAVE_ISINF=1', '-DHAVE_ISNAN=1', '-DHAVE_ISFINITE=1', '-DHAVE_EXPM1=1', '-DHAVE_LOG1P=1', '-DHAVE_ASINH=1', '-DHAVE_ACOSH=1', '-DHAVE_ATANH=1', '-DHAVE_RINT=1', '-DHAVE_TRUNC=1', '-DHAVE_EXP2=1', '-DHAVE_LOG2=1', '-DHAVE_HYPOT=1', '-DHAVE_CBRT=1', '-DHAVE_NEXTAFTER=1', '-DHAVE_CSIN=1', '-DHAVE_CCOS=1', '-DHAVE_CTAN=1', '-DHAVE_CSINH=1', '-DHAVE_CCOSH=1', '-DHAVE_CTANH=1', '-DHAVE_CASIN=1', '-DHAVE_CACOS=1', '-DHAVE_CATAN=1', '-DHAVE_CASINH=1', '-DHAVE_CACOSH=1', '-DHAVE_CATANH=1', '-DHAVE_CEXP=1', '-DHAVE_CLOG=1', '-DHAVE_CPOW=1', '-DHAVE_CSQRT=1', '-DHAVE_CABS=1', '-DHAVE_CARG=1', '-DHAVE_CIMAG=1', '-DHAVE_CREAL=1', '-DHAVE_CONJ=1', '-DHAVE_STRTOLL=1', '-DHAVE_STRTOULL=1', '-DHAVE_STRTOLD=1'] | ||
| EOF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This should all end up in one of the config.h files, not as command line flags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Not even that, if these checks actually fail, they can either be fixed innumpy/_core/meson.build or a simple skip for the checks can be added there. That goes forhas_function_sin et al. higher up too.
mattip commentedSep 22, 2025
We do have aarch64 testing base on github |
rgommers left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks for working on this@kfchou! I left some more detailed comments; I'd say the overall goal is to make the custom code we need to carry for this as small andnumpy-specific as possible, and having one CI job that tests that building an Android wheel actually works as intended.
Should I include the demo briefcase app for testing? Not sure how I should do that
No, that is undesirable. The right approach is running the test suite (or a relevant subset of it, depending on how show things run) under an emulator. Ongh-27698 it was pointed out that this is possible.
This build requires python 3.13. I'm not sure how to specify this requirement.
The general config files (pyproject.toml,cibw_before*,repair_*) should not make such an assumption, since they should work for any Python version >=3.13. In the CI job to test this cross build, 3.13 can be picked.
https://github.com/beeware/toga has examples of CI jobs that may be helpful here.
| set -e | ||
| set -x | ||
| # This script is designed to be called by cibuildwheecho "--- END WORKAROUND ---" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Accidental edit at the end of this sentence
| echo "CIBW_ARCHS: ${CIBW_ARCHS:-'(not set)'}" | ||
| echo "CIBW_ARCHS_ANDROID: ${CIBW_ARCHS_ANDROID:-'(not set)'}" | ||
| # Check for architecture in standard cibuildwheel environment variablesbuilding for Android. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
typo in "variablesbuilding"
| # WORKAROUND FOR CIBUILDWHEEL ISSUE: | ||
| # cibuildwheel documentation states that CIBW_ARCHS should be available for Android builds, | ||
| # but cibuildwheel 3.1.4 does NOT set these environment variables for Android. | ||
| # This appears to be a bug or incomplete implementation in cibuildwheel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It'd be good to fix that upstream incibuildwheel and add a link here to that issue or PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think this is a misunderstanding: cibuildwheel reads the CIBW variables as one possible means of configuration, it doesn't set them itself.
| # As a workaround, we detect the architecture from various sources: | ||
| # 1. Check if CIBW_ARCHS is already set (future-proofing) | ||
| # 2. Look for architecture hints in environment variables | ||
| # 3. Check process command line for architecture indicators |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
You already set this inpyproject.toml, so three different ways of handling it here seems like overkill?
| echo "--- Building for architecture: $TARGET_ARCH ---" | ||
| # Set the target API level from cibuildwheel's environment variable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Also already handled inpyproject.toml
| has_function_strtold = true | ||
| # Skip BLAS/LAPACK for Android to avoid complex math library dependencies | ||
| allow-noblas = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This goes in[tool.cibuildwheel.android] inpyproject.toml normally. There's already an example for 32-bit Windows there.
| # This ensures symbols like PyExc_ValueError and math functions are available | ||
| # Note: On Android, math functions are part of libc, not a separate libm | ||
| c_link_args = ['-lpython3.13'] | ||
| cpp_link_args = ['-lpython3.13'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
If this isn't handled correctly in Meson, that's where this should be fixed. That also avoids hardcoding the interpreter version here.
| # Override system library detection for Android - math functions are in libc | ||
| c_args = ['-DHAVE_SIN=1', '-DHAVE_COS=1', '-DHAVE_TAN=1', '-DHAVE_SINH=1', '-DHAVE_COSH=1', '-DHAVE_TANH=1', '-DHAVE_ASIN=1', '-DHAVE_ACOS=1', '-DHAVE_ATAN=1', '-DHAVE_ATAN2=1', '-DHAVE_EXP=1', '-DHAVE_LOG=1', '-DHAVE_LOG10=1', '-DHAVE_SQRT=1', '-DHAVE_FLOOR=1', '-DHAVE_CEIL=1', '-DHAVE_FABS=1', '-DHAVE_POW=1', '-DHAVE_FMOD=1', '-DHAVE_LDEXP=1', '-DHAVE_FREXP=1', '-DHAVE_MODF=1', '-DHAVE_COPYSIGN=1', '-DHAVE_FINITE=1', '-DHAVE_ISINF=1', '-DHAVE_ISNAN=1', '-DHAVE_ISFINITE=1', '-DHAVE_EXPM1=1', '-DHAVE_LOG1P=1', '-DHAVE_ASINH=1', '-DHAVE_ACOSH=1', '-DHAVE_ATANH=1', '-DHAVE_RINT=1', '-DHAVE_TRUNC=1', '-DHAVE_EXP2=1', '-DHAVE_LOG2=1', '-DHAVE_HYPOT=1', '-DHAVE_CBRT=1', '-DHAVE_NEXTAFTER=1', '-DHAVE_CSIN=1', '-DHAVE_CCOS=1', '-DHAVE_CTAN=1', '-DHAVE_CSINH=1', '-DHAVE_CCOSH=1', '-DHAVE_CTANH=1', '-DHAVE_CASIN=1', '-DHAVE_CACOS=1', '-DHAVE_CATAN=1', '-DHAVE_CASINH=1', '-DHAVE_CACOSH=1', '-DHAVE_CATANH=1', '-DHAVE_CEXP=1', '-DHAVE_CLOG=1', '-DHAVE_CPOW=1', '-DHAVE_CSQRT=1', '-DHAVE_CABS=1', '-DHAVE_CARG=1', '-DHAVE_CIMAG=1', '-DHAVE_CREAL=1', '-DHAVE_CONJ=1', '-DHAVE_STRTOLL=1', '-DHAVE_STRTOULL=1', '-DHAVE_STRTOLD=1'] | ||
| cpp_args = ['-DHAVE_SIN=1', '-DHAVE_COS=1', '-DHAVE_TAN=1', '-DHAVE_SINH=1', '-DHAVE_COSH=1', '-DHAVE_TANH=1', '-DHAVE_ASIN=1', '-DHAVE_ACOS=1', '-DHAVE_ATAN=1', '-DHAVE_ATAN2=1', '-DHAVE_EXP=1', '-DHAVE_LOG=1', '-DHAVE_LOG10=1', '-DHAVE_SQRT=1', '-DHAVE_FLOOR=1', '-DHAVE_CEIL=1', '-DHAVE_FABS=1', '-DHAVE_POW=1', '-DHAVE_FMOD=1', '-DHAVE_LDEXP=1', '-DHAVE_FREXP=1', '-DHAVE_MODF=1', '-DHAVE_COPYSIGN=1', '-DHAVE_FINITE=1', '-DHAVE_ISINF=1', '-DHAVE_ISNAN=1', '-DHAVE_ISFINITE=1', '-DHAVE_EXPM1=1', '-DHAVE_LOG1P=1', '-DHAVE_ASINH=1', '-DHAVE_ACOSH=1', '-DHAVE_ATANH=1', '-DHAVE_RINT=1', '-DHAVE_TRUNC=1', '-DHAVE_EXP2=1', '-DHAVE_LOG2=1', '-DHAVE_HYPOT=1', '-DHAVE_CBRT=1', '-DHAVE_NEXTAFTER=1', '-DHAVE_CSIN=1', '-DHAVE_CCOS=1', '-DHAVE_CTAN=1', '-DHAVE_CSINH=1', '-DHAVE_CCOSH=1', '-DHAVE_CTANH=1', '-DHAVE_CASIN=1', '-DHAVE_CACOS=1', '-DHAVE_CATAN=1', '-DHAVE_CASINH=1', '-DHAVE_CACOSH=1', '-DHAVE_CATANH=1', '-DHAVE_CEXP=1', '-DHAVE_CLOG=1', '-DHAVE_CPOW=1', '-DHAVE_CSQRT=1', '-DHAVE_CABS=1', '-DHAVE_CARG=1', '-DHAVE_CIMAG=1', '-DHAVE_CREAL=1', '-DHAVE_CONJ=1', '-DHAVE_STRTOLL=1', '-DHAVE_STRTOULL=1', '-DHAVE_STRTOLD=1'] | ||
| EOF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Not even that, if these checks actually fail, they can either be fixed innumpy/_core/meson.build or a simple skip for the checks can be added there. That goes forhas_function_sin et al. higher up too.
| import sysconfig | ||
| import os | ||
| # Check BLDLIBRARY configuration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Left-over debug code from here onwards?
| @@ -0,0 +1,142 @@ | |||
| #!/bin/bash | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This looks like it should be either a separate tool or part of Briefcase. It's not specific tonumpy, just a generic wheel repair utility.
kfchou commentedOct 7, 2025
Thanks for your feedback everyone.@rgommers, I'm slowly working through your comments. Admittedly, most of the this work is done by directing copilot/sonnet since I'm not experience with Meson or C. |
mhsmith commentedOct 12, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Unfortunately I found that none of GitHub's ARM runners can run the Android emulator (1,2). They can only run it on Linux x86_64.
I would strongly recommend doing this through cibuildwheel, as it automaticaly handles all the details of setting up Android build and test environments, starting an emulator, etc. However, on Android it does require the test command to be a |
| # Try different approaches to fix BLDLIBRARY issue | ||
| # The issue is meson-python is inserting literal '$(BLDLIBRARY)' in link commands | ||
| # For Android, we don't want to link Python extensions to libpython at all |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We absolutely do want to link them to libpython, but if it's using the Python .pc file to achieve this, then this may be affected bypython/cpython#138800.
mhsmith commentedDec 17, 2025
This PR has now been overtaken by#30412, so I suggest closing it. |
Uh oh!
There was an error while loading.Please reload this page.
Related to:#27698.
These configs enable you to run
cibuildwheel --platform androidto build android-compatible.whlfiles.You can use
briefcaseto specify these wheels when you want to build a python-based android app that usesnumpy. Seediscussion for details.Testing
I tested these wheels using a demo
briefcaseapp, importing numpy and get it to print out mathematical operations.Questions for reviewers:
briefcaseapp for testing? Not sure how I should do that