Skip to content

Feat: Android support#158

Open
jaoleal wants to merge 4 commits into
sedited:masterfrom
jaoleal:android_support
Open

Feat: Android support#158
jaoleal wants to merge 4 commits into
sedited:masterfrom
jaoleal:android_support

Conversation

@jaoleal

@jaoleal jaoleal commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

This pr contain 3 commits:

  1. Build instructions for android building, concise and aiming to be executed on the nix environment introduced in the second commit.
  2. Nix expressions on flake.nix gathering dependencies for building and testing the android output.
  3. CI runner that evaluates the nix expressions.

@jaoleal jaoleal mentioned this pull request Apr 10, 2026
@sedited

sedited commented Apr 23, 2026

Copy link
Copy Markdown
Owner

This looks nice, can you rebase this?

@jaoleal

jaoleal commented Apr 30, 2026

Copy link
Copy Markdown
Contributor Author

Changelog:

@jaoleal jaoleal force-pushed the android_support branch 6 times, most recently from a2c959f to 0f3252f Compare May 6, 2026 20:07
@jaoleal jaoleal changed the title POC: Android support Feat: Android support May 6, 2026
@jaoleal jaoleal marked this pull request as ready for review May 6, 2026 20:08
@jaoleal

jaoleal commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

I reduced a lot the code and i think this is the concise version to support android

@alexanderwiederin

alexanderwiederin commented May 7, 2026

Copy link
Copy Markdown
Collaborator

I don't think android is a supported target for libbitcoinkernel. Doesn't this require upstream work on bitcoin core first?

@alexanderwiederin alexanderwiederin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

From what I understand the ubuntu boost packages don't ship with the cmake config that core needs when cross-compiling.

Am I right that you got it working on nix locally? If so, can we stick with with only supporting the nix build for android?

Comment thread flake.nix Outdated
Comment thread flake.nix Outdated
@jaoleal

jaoleal commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

Am I right that you got it working on nix locally? If so, can we stick with with only supporting the nix build for android?

Yes, i worked all this on nix but Im not sure about leaving android building exclusively for nix, this would make it a direct dependency of the project and its not something really special that only nix can do. Besides the dependency problem, nix can drift versions because of nixpkgs releases and that can raise problems only by itself.

Therefore, i still would like for CI to keep the runner as ubuntu. Its easier for the general developer audience to replicate the build on their machine if they need

Edit: see the comment below

@jaoleal

jaoleal commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

Correction, I changed my mind... The idea is that the build.rs file is already bloated because of the android support additions, adding support for ubuntu bloated it even more... It looks like leaving to nix to cross-compile to android is actually a good choice, the changes stay minimal on build.rs side and it have broader support running on linux and macos machines... Ill make sure to document that somewhere and state how to make the android build.

@jaoleal jaoleal force-pushed the android_support branch 5 times, most recently from 479401e to 30f44a8 Compare May 8, 2026 00:24
@jaoleal

jaoleal commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

Okay the android build being exclusive for nix made things easier for this PR, the changes on build.rs are minimal... I included some inline doc comments so the reviewer can follow why each line were added.

I added a section on the readme explaining the android build but its not that explanatory in a level that one can learn how to build this lib to android, do you guys think thats needed ?

I can extend the docs to include instructions for one to reproduce it on a downstream build.rs, just tell me where to put it.
AFAIK is trivial for those using Kotlin, as mandacaru is using, to pull an already compiled shared object during build time. Thats what ill do on floresta-nix for mandacaru, ideally the CI would also offer the compiled objects too for those who might need it.

@alexanderwiederin alexanderwiederin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Great to see this working.

If we land the hand-written bindings PR (#163) first, the changes in build.rs should become simpler. I would suggest we wait for it.

Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix Outdated
Comment thread .github/workflows/ci.yml
Comment thread README.md Outdated
Comment thread README.md
@sedited

sedited commented May 20, 2026

Copy link
Copy Markdown
Owner

@jaoleal I'm interested in getting this change through. Can you rebase it and address Alex' comments?

@jaoleal

jaoleal commented May 20, 2026

Copy link
Copy Markdown
Contributor Author

@jaoleal I'm interested in getting this change through. Can you rebase it and address Alex' comments?

Yes, sorry for taking long... I was waiting for the bindgen pr to be merged so we had sure what that would imply here without rebasing on a pr

@alexanderwiederin alexanderwiederin linked an issue May 22, 2026 that may be closed by this pull request
@sedited

sedited commented May 25, 2026

Copy link
Copy Markdown
Owner

I'm also fine with just leaving it be for now and handling that in a follow-up pull request. Having something link is already a good assurance :)

@jaoleal jaoleal force-pushed the android_support branch 3 times, most recently from d5724e1 to 32115fc Compare May 25, 2026 18:14
@jaoleal

jaoleal commented May 25, 2026

Copy link
Copy Markdown
Contributor Author

Ok, done.

32115fc Addressed suggestions:

  • Moved changelog edits to unreleased section.
  • Added tests for the android outputs.
  • fixed formatting on string literals

cc @sedited take a look on https://github.com/sedited/rust-bitcoinkernel/actions/runs/26413972282/job/77754301637#step:4:6483

Comment thread libbitcoinkernel-sys/build.rs Outdated
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();

if target_os == "android" {
let ndk = env::var("ANDROID_NDK_HOME")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We are fetching this twice. Any chance we can reuse this?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How about we do the following in the outer scope:

let ndk = if is_android {
    Some(env::var("ANDROID_NDK_HOME")
        .expect("Android target detected but ANDROID_NDK_HOME is not set"))
} else {
    None
};

Then we can reuse it with .as_deref().unwrap() in the is_android blocks.

Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread flake.nix
Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread CHANGELOG.md Outdated
## [0.2.1] 2026-05-20

### Added
- Added Nix package outputs for Android with bundled NDK r27, Rust toolchains, Boost, and cmake.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This can be removed from the ## [0.2.1] 2026-05-20 section.

Comment thread libbitcoinkernel-sys/build.rs Outdated
@jaoleal jaoleal force-pushed the android_support branch from 32115fc to fab4004 Compare May 26, 2026 14:53
@jaoleal

jaoleal commented May 26, 2026

Copy link
Copy Markdown
Contributor Author

Applied @alexanderwiederin suggestions

@alexanderwiederin alexanderwiederin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Also reopened #158 (comment) which I think was not addressed.

Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix
Comment thread CHANGELOG.md Outdated
Comment thread README.md Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix
@jaoleal jaoleal force-pushed the android_support branch from fab4004 to e6af0a8 Compare June 1, 2026 17:48
@jaoleal

jaoleal commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Done, applied @alexanderwiederin suggestions

@alexanderwiederin alexanderwiederin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the wait!

Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread libbitcoinkernel-sys/build.rs Outdated
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();

if target_os == "android" {
let ndk = env::var("ANDROID_NDK_HOME")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How about we do the following in the outer scope:

let ndk = if is_android {
    Some(env::var("ANDROID_NDK_HOME")
        .expect("Android target detected but ANDROID_NDK_HOME is not set"))
} else {
    None
};

Then we can reuse it with .as_deref().unwrap() in the is_android blocks.

Comment thread libbitcoinkernel-sys/build.rs Outdated
Comment thread libbitcoinkernel-sys/build.rs
Comment thread libbitcoinkernel-sys/CHANGELOG.md Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix Outdated
Comment thread CHANGELOG.md
## [Unreleased]

### Added
- Added Nix package outputs for Android with bundled NDK r24, Rust toolchains, Boost, and cmake.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should this be r27? Judging by line 93 of flake.nix.

@jaoleal jaoleal Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, i had the same doubt, If you check on flake.nix, youll see that we dont use ANDROID_API_LEVEL = "24"; directly in the build process itself but its still declared as a variable for one to alter if needed, it would reflect also altering

       // API level 24+ is required because Bitcoin Core uses getifaddrs
       // which was introduced in Android API 24 (Nougat).
       //
       // This can be overridden to a higher level by setting ANDROID_API_LEVEL.
       let api_level = match env::var("ANDROID_API_LEVEL") {
           Ok(level) => {
               let n: u32 = level.parse().expect("ANDROID_API_LEVEL must be a number");
               assert!(n >= 24, "ANDROID_API_LEVEL must be 24+");
               level
           }
           _ => "24".to_string(),
       };

It appears that the API version is not the same number as the RELEASE version, the ndkVersion = "27.2.12479018"; that we use to declare the components release.

Ill add a comment clarifying that to avoid future confusion

Comment thread CHANGELOG.md Outdated
## [0.2.1] 2026-05-20

### Added
- Added Nix package outputs for Android with bundled NDK r27, Rust toolchains, Boost, and cmake.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This should not be here.

@jaoleal

jaoleal commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

Addressed @alexanderwiederin suggestions and fixes

@alexanderwiederin alexanderwiederin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Getting there! Could you update the PR description? I don't think it's a POC anymore. The PR also consists of four and not three commits.

Comment thread CHANGELOG.md Outdated
Comment thread .github/workflows/ci.yml
@jaoleal

jaoleal commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Getting there!

Gosh, I entered in automatic mode for this one... Sorry

jaoleal added 3 commits June 16, 2026 11:20
This commit introduces build instructions for building the kernel targetting android.

The instructions follows a design that is minimal, counting it will be executed in
the nix environment which will be implemented in the next commits.

We consciously made this decision; Nix runs on most systems where specific implementations
would otherwise be necessary for each one. Nix helps keep these instructions minimal and
reduces the chance of introducing bugs.
This commit introduces nix outputs in flake.nix that prepares the
environment gathering dependencies that the Android build instructions
needs and testing instructions.

Testing android outputs is restricted to x86_64-linux and automatically
triggered when the build process ends. QEMU user-mode emulation is
configured as the Cargo test runner for cross-compiled Android targets.
@jaoleal

jaoleal commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Changelog:

  • I reworded some commits into better and descriptive messages.
  • I squashed the last commit that introduce test preparation into the commit that introduced the nix build instructions, so the nix changes are final. The commit message should also explain that testing is restricted to select capable hosts.
  • I removed a variable and the newly introduced methods and inline their logic. I think this helps readers to understand whats necessary only for the android scope. Also, the less diff the better ?

@jaoleal

jaoleal commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Just a thing, since the android outputs can only be built with nix, I still didnt found a way to integrate it on floresta upstream so what im planning is to offer the compiled binaries on floresta-nix with the current patches presented here.

I know that this is more a floresta problem but I think other projects, those depending on rust-bitcoinkernel as floresta does, may lead into the same problem and maybe a good solution would be if this project offered its own pre-compiled Android artifacts, what you guys think about it ?

…LIB_DIR

When the LIBBITCOINKERNEL_LIB_DIR environment variable is set, build.rs
skips the CMake configure/build/install steps entirely and links against
the pre-built static library at the given path. This follows the same
pattern as openssl-sys with OPENSSL_LIB_DIR.

This allows builders to pre-compile libbitcoinkernel separately and point
the sys crate at the result, rather than needing adding patches to its
projects.
@Davidson-Souza

Copy link
Copy Markdown

Since yesterday I'm experimenting with this PR and integrating Floresta with Maven, so Android devs can consume Floresta as any other library. We already had some scaffolding in floresta-ffi but couldn't build bitcoinkernel due to the things fixed here.

I've opened getfloresta/floresta-ffi#11 fixing it, I can now build and run floresta with kernel enabled. Writing the main pain points here for reviewers and future reference. All my experiments did not use Nix. I've coded this on Arch Linux and Ci runs on Ubuntu.

  • NDK couldn't find boost's headers in the host system. I had to symlink them to my ndk folder. This is kinda ugly, currently looking for a better approach
  • export Boost_DIR and CMAKE_PREFIX_PATH, which is fine
  • I also had to vendor libc++_shared.so because it kept loading what Android calls the system STL. This is a dummy STL with only new/delete. When kernel tries to use some C++ name, I would get a linker error. I'm currently digging the docs to figure a better way to do that.
  • Something during the build is using a static version of android's libc, but using the symbol at runtime without explicitly mentioning it to the linker, so it segfaults on runtime. I still didn't really get what's going on, but it seems not related to kernel or C++.

a minor nit I've found when debugging this is that sometimes build.rs just ignores cmake's output, so it can silently fail and get a cryptic error about not finding the shared object. You can fix this with something like:

    let install_output = Command::new("cmake")
            .arg("--install")
            .arg(&build_dir)
            .arg("--config")
            .arg(build_config)
            .output()
            .unwrap();

        if !install_output.status.success() {
            let stdout = String::from_utf8_lossy(&install_output.stdout);
            let stderr = String::from_utf8_lossy(&install_output.stderr);
            panic!(
                "cmake --install failed with status {}.\nstdout:\n{}\nstderr:\n{}",
                install_output.status, stdout, stderr
            );
    }

@sedited

sedited commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Thanks for the report @Davidson-Souza! I hope we can get rid of boost soonish, there is some work happening towards that on the Bitcoin Core side.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: add cross-compilation job for 32-bit/Android targets

4 participants