-
Notifications
You must be signed in to change notification settings - Fork 294
feat(android): add Rust cross-compilation setup for Android environment #2650
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 our terms of service and privacy 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
|
For Rust projects built with Maturin, it currently does not work. Maturin has some cross-compilation issues on Android that still need to be fixed. For details, please see PyO3/maturin#2810 |
|
This looks nice and neat! Is there an example of it working in a real project that you've been testing it with? |
|
I want to test, but I did not know how to run this without the github action,if you know how to do, you can tell me,and I will test it. This commit is a modification I made based on the actual missing environment configuration built on Android using cbuildwheel. Of course, I manually configured it externally in a non-isolated environment, and after the configuration, I built the wheel correctly and it can run on Android |
|
You can test a project using something like this in a github workflow- - name: Build wheels
uses: ririv/cibuildwheel@main |
1384753 to
99ee18a
Compare
…_DIR to link against libpython3.x.so explicitly
|
Thanks, I have tested it, and made some new commits. Now, it works.
The
|
|
https://github.com/ririv/android-wheels/blob/main/.github/workflows/cbuildweel-repair-test.yml Here are some logs:
|
|
Looks good to me! @mhsmith what do you think? |
|
Sorry for the delay, I'll look at this as soon as I can. |
cibuildwheel/platforms/android.py
Outdated
| log.notice("Not overriding PYO3_CROSS_LIB_DIR as it has already been set") | ||
| else: | ||
| env["PYO3_CROSS_LIB_DIR"] = str(python_dir / "prefix" / "lib") | ||
| log.notice("Setting PYO3_CROSS_LIB_DIR for PyO3 cross-compilation") |
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 logging is unnecessary.
cibuildwheel/platforms/android.py
Outdated
| # CARGO_BUILD_TARGET is the variable used by Cargo and setuptools_rust | ||
| if env.get("CARGO_BUILD_TARGET"): | ||
| if env["CARGO_BUILD_TARGET"] != cargo_target: | ||
| log.notice("Not overriding CARGO_BUILD_TARGET as it has already been set") |
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 can't think of a plausible reason for the user to override any of these variables, so let's set them all unconditionally. This will make both functions so much shorter, that they might as well be combined into a single setup_rust_cross_compile function.
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.
Or even just setup_rust, since everything in this file is cross compiling by definition.
cibuildwheel/platforms/android.py
Outdated
| python_dir: Path, | ||
| env: MutableMapping[str, str], | ||
| ) -> None: | ||
| # All Python extension modules must therefore be explicitly linked against libpython3.x.so when building 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.
| # All Python extension modules must therefore be explicitly linked against libpython3.x.so when building for Android. | |
| # All Python extension modules must be explicitly linked against libpython3.x.so when building for Android. |
cibuildwheel/platforms/android.py
Outdated
| env: MutableMapping[str, str], | ||
| ) -> None: | ||
| cargo_target = android_triplet(python_configuration.identifier) | ||
| call("rustup", "target", "add", cargo_target) |
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 will fail if rustup isn't installed, so that must be handled.
Even if it is installed, it would be a waste of time to download Android Rust files for packages that don't actually use Rust. How long will this take? If it's more more than a couple of seconds, I don't think that's acceptable.
Is the rustup target add command still necessary even if CARGO_BUILD_TARGET is set? If so, Is there some way we could trigger the command only for packages that use Rust?
For example, if calling rustup is part of the build process (I don't know whether it is), then we could add a rustup script to the environment's bin directory, and have it run rustup target add before forwarding the command to the real rustup. I was thinking of doing something similar to install the Android Fortran compiler on demand for those packages that attempt to use it.
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.
Copilot adds:
the Windows implementation (lines 206-232 in windows.py) does not call rustup at all - it only sets environment variables. This inconsistency should be evaluated to determine if rustup installation is actually necessary
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.
Pull request overview
This pull request adds Rust cross-compilation setup for the Android platform, mirroring similar functionality that exists for Windows. The implementation configures environment variables necessary for building Rust-based Python packages (using setuptools-rust and PyO3) when cross-compiling for Android targets.
Key Changes:
- Added
setup_rust_cross_compile()function to configure Cargo build target and linker environment variables - Added
setup_PYO3_cross_compile()function to set PyO3 cross-compilation library directory - Integrated both functions into the Android environment setup process
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
cibuildwheel/platforms/android.py
Outdated
| ) | ||
| env["CARGO_BUILD_TARGET"] = cargo_target | ||
| # CC has already been set by calling android.py (it calls android-env.sh) | ||
| env[f"{cargo_target_linker_env_name}"] = env["CC"] |
Copilot
AI
Dec 21, 2025
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.
Unnecessary f-string formatting. The variable cargo_target_linker_env_name is already a string, so wrapping it in an f-string is redundant. Change env[f"{cargo_target_linker_env_name}"] to env[cargo_target_linker_env_name] for cleaner code.
| env[f"{cargo_target_linker_env_name}"] = env["CC"] | |
| env[cargo_target_linker_env_name] = env["CC"] |
cibuildwheel/platforms/android.py
Outdated
| else: | ||
| log.warning(f"Unable to configure Rust cross-compilation for architecture {cargo_target}") |
Copilot
AI
Dec 21, 2025
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.
The else branch on line 428 is unreachable. The android_triplet function always returns a non-empty string from the ANDROID_TRIPLET dictionary (see lines 39-42, 54-55). If the identifier is invalid, parse_identifier would raise a ValueError before reaching this point, so cargo_target will always be truthy. This dead code should be removed, or if there's a possibility of empty/None values, the logic needs to be adjusted.
cibuildwheel/platforms/android.py
Outdated
| def setup_rust_cross_compile( | ||
| python_configuration: PythonConfiguration, | ||
| env: MutableMapping[str, str], | ||
| ) -> None: | ||
| cargo_target = android_triplet(python_configuration.identifier) | ||
| call("rustup", "target", "add", cargo_target) | ||
|
|
||
| # CARGO_BUILD_TARGET is the variable used by Cargo and setuptools_rust | ||
| if env.get("CARGO_BUILD_TARGET"): | ||
| if env["CARGO_BUILD_TARGET"] != cargo_target: | ||
| log.notice("Not overriding CARGO_BUILD_TARGET as it has already been set") | ||
| # No message if it was set to what we were planning to set it to | ||
| elif cargo_target: | ||
| cargo_target_linker_env_name = ( | ||
| f"CARGO_TARGET_{cargo_target.upper().replace('-', '_')}_LINKER" | ||
| ) | ||
| log.notice( | ||
| f"Setting CARGO_BUILD_TARGET={cargo_target} and {cargo_target_linker_env_name} for cross-compilation" | ||
| ) | ||
| env["CARGO_BUILD_TARGET"] = cargo_target | ||
| # CC has already been set by calling android.py (it calls android-env.sh) | ||
| env[f"{cargo_target_linker_env_name}"] = env["CC"] | ||
| else: | ||
| log.warning(f"Unable to configure Rust cross-compilation for architecture {cargo_target}") | ||
|
|
||
|
|
||
| def setup_PYO3_cross_compile( | ||
| python_dir: Path, | ||
| env: MutableMapping[str, str], | ||
| ) -> None: | ||
| # All Python extension modules must therefore be explicitly linked against libpython3.x.so when building for Android. | ||
| # See: https://peps.python.org/pep-0738/#linkage | ||
| # For projects using PyO3, this requires setting PYO3_CROSS_LIB_DIR to the directory containing libpython3.x.so. | ||
| # See: https://pyo3.rs/v0.27.1/building-and-distribution.html#cross-compiling | ||
| if env.get("PYO3_CROSS_LIB_DIR"): | ||
| log.notice("Not overriding PYO3_CROSS_LIB_DIR as it has already been set") | ||
| else: | ||
| env["PYO3_CROSS_LIB_DIR"] = str(python_dir / "prefix" / "lib") | ||
| log.notice("Setting PYO3_CROSS_LIB_DIR for PyO3 cross-compilation") |
Copilot
AI
Dec 21, 2025
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.
The new Rust cross-compilation setup functions lack test coverage. Given that test/test_android.py has comprehensive test coverage for other Android functionality, tests should be added to verify that setup_rust_cross_compile and setup_PYO3_cross_compile correctly set the expected environment variables (CARGO_BUILD_TARGET, CARGO_TARGET_*_LINKER, and PYO3_CROSS_LIB_DIR) under various conditions.
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.
Rather than checking for the environment variables directly, it would be better to actually build and run a simple Rust project, just as we currently do for C++ in test_android.py::test_libcxx.
cibuildwheel/platforms/android.py
Outdated
| for key in ["CFLAGS", "CXXFLAGS"]: | ||
| android_env[key] += " " + opt | ||
|
|
||
| # Cargo target linker need to be specified after CC is set |
Copilot
AI
Dec 21, 2025
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 comment: "need" should be "needs". The comment should read "Cargo target linker needs to be specified after CC is set".
| # Cargo target linker need to be specified after CC is set | |
| # Cargo target linker needs to be specified after CC is set |
… cargo and rustup
for more information, see https://pre-commit.ci
|
Thanks for the suggestions. I've updated the PR to address the feedback:
|
|
Since PyO3/maturin#2825 has been merged into main, we can now use cibuildwheel to test Rust projects built with maturin. However, as a new version hasn't been released yet, we have to build maturin from source for now. This is the GItHub Action script: This is the logs:
Sorry, there are still some issues with the maturin integration: it's building for Linux instead of Android. This might be a problem with the
However, we can still use a conversion tool to transform maturin projects into setuptools-rust projects and successfully build Android wheels.
|
|
I have investigated the issue with the wheel generated by maturin. It actually produced the correct wheel, but the tag was incorrect. This issue is unrelated to the current PR. So, no modification is necessary. |
|
Thanks; I'm on vacation at the moment, but I'll look at this in the new year. |
Like platform
windowscibuildwheel/cibuildwheel/platforms/windows.py
Lines 206 to 232 in c53e541
Add Rust cross-compilation setup for Android environment, it can fix the cross-compilation problem for the rust project built with setuptools-rust