Code Monkey home page Code Monkey logo

cargo-ndk-android-gradle's Introduction

Cargo NDK for Android projects

Allows building Rust code via cargo ndk command in android projects.

It is somewhat similar to the Mozilla Rust Android Gradle Plugin, however, it uses cargo ndk to find the right linker and ar and build the project. Also, it allows configuring rust release profile (dev vs release) for each gradle buildType. Actually, any options can be configured per gradle buildType, it works similar to android configuration.

Gradle Plugin Page.

Usage

Add the plugin to your root build.gradle, like:

buildscript {
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "gradle.plugin.com.github.willir.rust:plugin:0.3.4"
    }
}

In your project's build.gradle, apply plugin and add the cargoNdk configuration (optionally):

android { ... }

apply plugin: "com.github.willir.rust.cargo-ndk-android"

// The following configuration is optional and works the same way by default
cargoNdk {
    buildTypes {
        release {
            buildType = "release"
        }
        debug {
            buildType = "debug"
        }
    }
}

Install rust toolchains:

rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android

Install cargo-ndk:

cargo install cargo-ndk

If you already have cargo-ndk, please make sure it is up to date:

cargo install --force cargo-ndk

Next, you need to specify path to NDK via either setting ANDROID_NDK_HOME env variable, or ndk.dir property in local.properties.

This plugin adds the following targets: buildCargoNdkDebug, buildCargoNdkRelease, however, they should be run automatically by building your android project as usual. So:

  1. ./gradlew assembleDebug will build dev (debug) profile. Depends on, and so will run buildCargoNdkDebug.
  2. ./gradlew assembleRelease will build release profile. Depends on, and so will run buildCargoNdkRelease.

Configuration

All options

cargoNdk {
    // List of all targets
    // By default: ["arm64", "arm", "x86", "x86_64"]
    targets = ["arm64", "arm", "x86", "x86_64"]

    // Path to directory with rust project
    // By default: "app/src/main/rust"
    module = "../rust"

    // Path to rust 'target' dir (the dir where build happens), relative to module
    // By default: "target"
    targetDirectory = "target"

    // List of all library names to copy from target to jniLibs
    // By default parses Cargo.toml and gets all dynamic libraries
    librariesNames = ["libmy_library.so"]

    // The apiLevel to build link with
    // By default: android.defaultConfig.minSdkVersion
    apiLevel = 19

    // Whether to build cargo with --offline flag
    // By default: false
    offline = true

    // The rust profile to build
    // Possible values: "debug", "release", "dev" (an alias for "debug")
    // By default: "release" for release gradle builds,
    //             "debug"   for debug   gradle builds
    buildType = "release"

    // Extra arguments to pass to cargo command
    // By default: []
    extraCargoBuildArguments = ["--offline"]

    // Extra environment variables
    // By default: [:]
    extraCargoEnv = ["foo": "bar"]

    // Whether to pass --verbose flag to cargo command
    // By default: false
    verbose = true
}

As it was already mentioned, any of those options can be configured separately for each buildTypes:

cargoNdk {
    apiLevel = 19  // default

    buildTypes {
        debug {
            apiLevel = 26  // overwrite for debug
        }
    }
}

ANDROID_NDK_HOME env variable

One way to specify path to NDK root for cargo-ndk is to set ANDROID_NDK_HOME. In the most common Linux case, you would need to set it in both ~/.bashrc (for terminal usage) and ~/.profile (for Android Studio usage); read ~/.bashrc vs ~/.profile. I usually have a separate .env_setup file, which is included in both ~/.bashrc and ~/.profile.

Usually, after updating ~/.profile, you need to relogin to see the effect.

Read about ~/.bashrc vs ~/.profile.

ndk.dir in local.properties

Instead of specifying ANDROID_NDK_HOME env variable, you can set ndk.dir in local.properties file.

Specify target via gradle property

You can also compile only one target by specifying the rust-target property to gradle. E.g. to build only arm64 target you can: gradle assembleDebug -Prust-target=arm64. It can be useful during development to speed up each build via not rebuilding targets that are not used during testing.

Troubleshooting

Rust error messages

To get the full error message in Android Studio - select the build tab at the bottom of Android Studio, and then select the topmost error group (Build: failed at); it should show you the full log.

cargo-ndk-android-gradle's People

Contributors

willir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

cargo-ndk-android-gradle's Issues

Consider declaring Gradle outputs to speed up build.

Android Studio provides the following warning about the NDK plugin:

At 14:26, Nov 30, 2021, Android Studio detected the following issue(s) with Gradle plugin com.github.willir.rust.cargo-ndk-android

Always-Run Tasks
Task runs on every build because it declares no outputs.

Plugin: com.github.willir.rust.cargo-ndk-android
Task: buildCargoNdkDebug
Task type: com.github.willir.rust.CargoNdkBuildTask
Issues for the same task were detected in 1 module(s), total execution time was 3.3s (11.6%), by module:
  Execution mode: FULL, time: 3.3s (11.6%), determines build duration: true, on critical path: false, issues: Always-Run Tasks

====Build information:====
Execution date: 11/30/21, 2:26 PM
Total build duration: 38.9s
Configuration time: 7.6s (19.6%)
Critical path tasks time: 28.9s (74.2%)
Critical path tasks size: 47
AGP versions: 7.0.3
====Platform information:====
AI-203.7717.56.2031.7784292, JRE 11.0.10+0-b96-7249189x64 JetBrains s.r.o., OS Linux(amd64) v5.10.74.3-microsoft-standard-WSL2, screens 3840.0x2160.0, 3840.0x2160.0

AS: Arctic Fox | 2020.3.1 Patch 3; Kotlin plugin: 203-1.6.0-release-798-AS7717.8; Android Gradle Plugin: 7.0.3; Gradle: 7.0.2; Gradle JDK: version 11.0.10; NDK: from local.properties: (not specified), latest from SDK: (not found); LLDB: pinned revision 3.1 not found, latest from SDK: (package not found); CMake: from local.properties: (not specified), latest from SDK: (not found), from PATH: 3.16.3

It only takes 3.3 seconds when the Rust code was unchanged. However, it would be nice if even that could be saved.

about package target folder

in my condition, i need package and copy archive to a lib module. so i modify the plugin, for now, if we apply the plugin in app.gradle it will copy archive to app module, if we apply in a library it will copy archive to library module. #4

cargo ndk error libsodium-sys

not sure if this is the place to ask. Am building rustdesk android app. ran into this problem when running the command
cargo ndk --platform 21 --target aarch64-linux-android build --release --features flutter
here is the last section of the error
error: failed to run custom build command for libsodium-sys v0.2.7
Caused by:
process didn't exit successfully: /Users/MBP15/projects/rustdesk/target/release/build/libsodium-sys-2cc6cbbf5c519475/build-script-build (exit status: 101)
--- stdout
cargo:rerun-if-env-changed=SODIUM_LIB_DIR
cargo:rerun-if-env-changed=SODIUM_SHARED
cargo:rerun-if-env-changed=SODIUM_USE_PKG_CONFIG
cargo:rerun-if-env-changed=SODIUM_DISABLE_PIE
OPT_LEVEL = Some("3")
TARGET = Some("aarch64-linux-android")
HOST = Some("x86_64-apple-darwin")
cargo:rerun-if-env-changed=CC_aarch64-linux-android
CC_aarch64-linux-android = Some("/Users/MBP15/Library/Android/sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang")
cargo:rerun-if-env-changed=CFLAGS_aarch64-linux-android
CFLAGS_aarch64-linux-android = None
cargo:rerun-if-env-changed=CFLAGS_aarch64_linux_android
CFLAGS_aarch64_linux_android = None
cargo:rerun-if-env-changed=TARGET_CFLAGS
TARGET_CFLAGS = None
cargo:rerun-if-env-changed=CFLAGS
CFLAGS = None
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some("false")
checking build system type... x86_64-apple-darwin21.6.0
checking host system type... aarch64-unknown-linux-android
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for aarch64-linux-android-strip... no
checking for strip... strip
checking for a thread-safe mkdir -p... build-aux/install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking whether UID '501' is supported by ustar format... yes
checking whether GID '20' is supported by ustar format... yes
checking how to create a ustar tar archive... gnutar
checking whether make supports nested variables... (cached) yes
checking whether to enable maintainer-specific portions of Makefiles... no
checking whether make supports the include directive... yes (GNU style)
checking for aarch64-linux-android-gcc... /Users/MBP15/Library/Android/sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang
checking whether the C compiler works... no

--- stderr
configure: error: in /Users/MBP15/projects/rustdesk/target/aarch64-linux-android/release/build/libsodium-sys-bc031ec13d20478a/out/source/libsodium': configure: error: C compiler cannot create executables See config.log' for more details
thread 'main' panicked at '
Failed to configure libsodium using cd "/Users/MBP15/projects/rustdesk/target/aarch64-linux-android/release/build/libsodium-sys-bc031ec13d20478a/out/source/libsodium" && CC="/Users/MBP15/Library/Android/sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang" CFLAGS="-O3 -DANDROID -ffunction-sections -fdata-sections -fPIC --target=aarch64-linux-android -Wall -Wextra" "/Users/MBP15/projects/rustdesk/target/aarch64-linux-android/release/build/libsodium-sys-bc031ec13d20478a/out/source/libsodium/configure" "--prefix=/Users/MBP15/projects/rustdesk/target/aarch64-linux-android/release/build/libsodium-sys-bc031ec13d20478a/out/installed" "--libdir=/Users/MBP15/projects/rustdesk/target/aarch64-linux-android/release/build/libsodium-sys-bc031ec13d20478a/out/installed/lib" "--host=aarch64-linux-android" "--enable-shared=no"
CFLAGS=-O3 -DANDROID -ffunction-sections -fdata-sections -fPIC --target=aarch64-linux-android -Wall -Wextra
CC=/Users/MBP15/Library/Android/sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang


Possible missing dependencies.
See https://github.com/sodiumoxide/sodiumoxide#cross-compiling


', /Users/MBP15/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libsodium-sys-0.2.7/build.rs:257:9
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
[2023-06-29T03:34:26Z INFO cargo_ndk::cli] If the build failed due to a missing target, you can run this command:
[2023-06-29T03:34:26Z INFO cargo_ndk::cli]
[2023-06-29T03:34:26Z INFO cargo_ndk::cli] rustup target install aarch64-linux-android
`

Consider building for desktop

I've hit a snag where I'm trying to run unit tests with Junit on my bindings to make sure everything works nicely. Unfortunately I keep hitting the following error: no core in java.library.path. After a lot of searching i think its the fact that the libraries built are for the android os using cargo-ndk and there's no way to build for the desktop like the mozilla plugin does. Unfortunately that plugin does not work for me either because of an issue in discovering cargo

Suggestion: Leave `jniLibs` folder layout up to `cargo-ndk`

Since cargo-ndk can already move the built native libraries into folders named after the Android ABI names (as is expected in jniLibs), why do this manually here using enum RustTargetType?

PS. This is an amazing project, it's exactly what I needed, thank you so much! I hope it won't succumb to bitrot anytime soon!

Show the errors when cargo build fails?

Currently if the cargo ndk build fails, android studio only shows that cargo exited with a non 0 return code. To see the actual error you have to compile it manually in command line (AFAIK anyway).

Would be nice to be able to see the error directly in android studio, especially for cases when manually compiling it works, but fails when building from android studio. (Usually caused by some environment variable differences).

Can't find cargo on Windows

I'm looking at isFoundInPath, and it seems like you're looking for an exact match. I'm guessing you'd need to look for "cargo.exe" on Windows. I definitely have it in my path, and confirm that the plugin prints out its directory in the exception.

I'd submit a PR, but a) I'm not sure how to detect Windows in Gradle tasks and b) I can't seem to build my app against my checkout of the plugin. I set the dependency version to + and created a settings.gradle like this one. I.e.:

includeBuild('../../../../src/cargo-ndk-android-gradle') {
    dependencySubstitution {
        // As required.
        substitute module('gradle.plugin.com.github.willir.rust:plugin') with project(':plugin')
    }
}

But that didn't work. Advice welcome.

Thanks.

Including libc++_shared.so

One of my rust dependencies links to the shared version of the C++ STL libc++. (Specifically, I'm trying to use oboe-rs with the shared-stdcxx feature.)

After building this all with the cargo ndk gradle plugin, I'm getting link errors at runtime: java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found

From reading here (also a later section in that page) and here, it sounds like if you link to libc++_shared.so you need to include it in your app. Moreover it says that if you use gradle, this should be done for you.

Since this is a gradle plugin, does that mean that it's this plugin's job to make that happen? I don't know if this logic is sound - I am completely out of my depth here just trying to get something working. But I thought I'd try raising an issue in case it is the job of this plugin. Also, if anyone has any insight as to how to go this manually / some other way, I'd love to hear it.

Obscure error when trying to build

This is my first time using this plugin so I'm not sure I have everything set up correctly but I followed the directions correctly afaik. Anyways, I'm getting this error:

Execution failed for task ':app:buildCargoNdkDebug'.
A problem occurred starting process 'command 'cargo''

Cause: error=2, No such file or directory
Idk what it means or how to fix it. I have cargo installed and it's runnable by a new terminal.

Cleaning

Hi.

First of all, thanks for making this plugin! We are using it in touchHLE and it has worked quite well for us.

Something that's caught me out occasionally is that the building is integrated, but not the cleaning. If I tell Android Studio to clean up the project, that isn't passed on to Cargo.

I'm not sure if this is good or badโ€ฆ so I'm not sure if it should be changed. But maybe it'd be worth mentioning in the README.

Failure if local.properties is not present?

Please accept my apologies in advance if this is not a particularly well formulated issue, as I am a Rust developer first and a JDK developer like... 25th ๐Ÿ˜‚

It seems like local.properties needs to be present, or the build just fails. I knew exactly enough about Gradle to be dangerous, but Im' confused by this since my autogenerated local.properties file specifically says not to commit it to git, and running GitHub actions there is, as far as I can tell, no reason this would be generated for you and no reason to create one in most cases.

For a concrete example, see this failed CI run: https://github.com/stadiamaps/ferrostar/actions/runs/6761866916/job/18377186924.

java.io.FileNotFoundException: /home/runner/work/ferrostar/ferrostar/android/local.properties (No such file or directory)

I fixed this by literally adding touch local.properties in my GitHub action. This seems to me like it should not be necessary. Am I missing something?

Doesn't automatically detect cdylib targets

As of right now, the code seemingly only automatically copies dylib targets:

return rootPackage.targets
.findAll { it.kind.indexOf("dylib") != -1 }
.collect { "lib" + (String) it.name + ".so" }

I don't really know what the difference is, but the jni crate docs say to use cdylib, so I think it'd make sense to detect both: https://docs.rs/jni/0.18.0/jni/#the-rust-side

Exception when `cargoNdk.module` is set

I specify the path to rust code like below:

cargoNdk {
    module = '../../backend'
}

But an exception occurs:

FAILURE: Build failed with an exception.

* Where:
Build file 'android/app/build.gradle' line: 72

* What went wrong:
A problem occurred evaluating project ':app'.
> Cannot cast object '../../backend' with class 'java.lang.String' to class 'java.nio.file.Path'

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

The output of gradle --version:

------------------------------------------------------------
Gradle 5.6.2
------------------------------------------------------------

Build time:   2019-09-05 16:13:54 UTC
Revision:     55a5e53d855db8fc7b0e494412fc624051a8e781

Kotlin:       1.3.41
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.14 compiled on March 12 2019
JVM:          1.8.0_222 (Oracle Corporation 25.222-bga)
OS:           Linux 4.19.81 amd64

Use local.properties' path to ndk?

The way I usually setup my projects is by setting ndk.dir (and sdk.dir) in project's local.properties, and I build using ./gradlew assembleRelease.

This doesn't work, because cargo-ndk exclusively use environment variables, and it looks like gradle doesn't set the environment to the program.

Since cargo-ndk 0.6.1, ANDROID_NDK_HOME is favored: bbqsrc/cargo-ndk@25402db

So ideally cargo-ndk-android-gradle should copy ndk.dir into ANDROID_NDK_HOME

Cargo NDK arguments changed

It looks like cargo-ndk introduced a breaking change with it's 2.0 release, changing the --target & --platform arguments. When I install cargo-ndk with cargo install cargo-ndk --version 1.0.0 it does work.

Maybe it's an idea to also verify the major version of the installed cargo-ndk?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.