{"id":20590083,"url":"https://github.com/otavia-projects/mill-rust-jni","last_synced_at":"2025-04-14T22:26:44.330Z","repository":{"id":154574788,"uuid":"586139253","full_name":"otavia-projects/mill-rust-jni","owner":"otavia-projects","description":"A mill plugin for build rust jni code!","archived":false,"fork":false,"pushed_at":"2023-07-21T10:35:17.000Z","size":81,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-28T10:47:32.127Z","etag":null,"topics":["jni","mill-plugin","rust"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/otavia-projects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-07T04:18:51.000Z","updated_at":"2023-11-16T00:15:07.000Z","dependencies_parsed_at":"2024-11-16T07:44:15.438Z","dependency_job_id":null,"html_url":"https://github.com/otavia-projects/mill-rust-jni","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/otavia-projects%2Fmill-rust-jni","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/otavia-projects%2Fmill-rust-jni/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/otavia-projects%2Fmill-rust-jni/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/otavia-projects%2Fmill-rust-jni/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/otavia-projects","download_url":"https://codeload.github.com/otavia-projects/mill-rust-jni/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248970660,"owners_count":21191468,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jni","mill-plugin","rust"],"created_at":"2024-11-16T07:33:57.642Z","updated_at":"2025-04-14T22:26:44.324Z","avatar_url":"https://github.com/otavia-projects.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=center\u003e\n\u003c/div\u003e\n\u003ch1 align=center\u003emill-rust-jni\u003c/h1\u003e\n\n\u003cp align=center \u003e\u003cb\u003eA mill plugin for build rust jni code!\u003c/b\u003e\u003c/p\u003e\n\n![GitHub](https://img.shields.io/github/license/otavia-projects/mill-rust-jni)\n![Maven Central](https://img.shields.io/maven-central/v/io.github.otavia-projects/mill-rust_mill0.10_2.13)\n![Sonatype Nexus (Releases)](https://img.shields.io/nexus/r/io.github.otavia-projects/mill-rust_mill0.10_2.13?server=https%3A%2F%2Fs01.oss.sonatype.org)\n![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.otavia-projects/mill-rust_mill0.10_2.13?server=https%3A%2F%2Fs01.oss.sonatype.org)\n\n\u003chr\u003e\n\nLanguage: [简体中文](./README.zh_cn.md)\n\n\u003chr\u003e\n\n## Example\n\n[rust-scala-demo](https://github.com/yankun1992/rust-scala-demo)\n\n## Setup\n\nIn your project build script `build.sc`, import the plugin with the following code:\n\n```scala\nimport $ivy.`io.github.otavia-projects::mill-rust_mill$MILL_BIN_PLATFORM:{version}`\nimport io.github.otavia.jni.plugin.RustJniModule\n```\n\nThen define a jni source code module, the module name `libjni` can be anything you like.\n\n```scala\nobject libjni extends RustJniModule {\n\n}\n```\n\nYou can then choose to generate a rust jni project template using the following command\n\n```shell\nmill libjni.nativeInit\n```\n\nThis command will generate the `native` directory in the `libjni` module, the `native` directory is A simple `Cargo`\nproject with the following project directory structure.\n\n```text\n|-- libjni\n|   |-- native\n|   |   |-- Cargo.toml\n|   |   |-- src\n|   |   |   |-- lib.rs\n\n```\n\nYou can of course create the `native` project structure manually, but if the `native` directory already exists\nthe `nativeInit` command will be ignored.\n\n### Customized settings\n\nThe `RustJniModule` contains several special definitions that you can override.\n\n| Definition        | Description                                                                               |\n|-------------------|-------------------------------------------------------------------------------------------|\n| defaultNativeName | Define the jni library name for the `nativeInit` command to generate the project template |\n| release           | Define cargo build mode                                                                   |\n| cargoBuildEnvs    | Environment variables used in `cargo build`. Since 0.2.0                                  | \n\nAlso contains the following commands or targets.\n\n| Definition           | Description                                                                                                                                                                      |\n|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| nativeName           | jni library name, parsed from Cargo.toml [package].name                                                                                                                          |\n| rustSourceRoot       | rust source code root, i.e. {module}/native                                                                                                                                      |\n| localTarget          | The rust target that can be run on the current computer, set using the environment variable MILL_RUST_TARGET                                                                     |\n| crossTargets         | The targets supported by rust cross-compilation are set using the environment variable MILL_CROSS_RUST_TARGET, with a comma separating the targets                               |\n| compileNative        | Compiling rust code                                                                                                                                                              |\n| otherNativeLibraries | Other exists native library, must contains `native` dir in it.                                                                                                                   |\n| resources            | The output of `compileNative` and `otherNativeLibraries` are appended to `resources`, so the resulting binary library is automatically included in the module's `localClasspath` |\n\n## Building jar packages\n\nSince the results of `compileNative` are automatically appended to the `resources` of the module, the jar package of the\nmodule built with mill will include all the generated binary libraries.\njar package will contain the following directory structure.\n\n```text\n|-- native\n|   |-- {rust_target1}\n|   |   |-- {library_name}\n|   |-- {rust_target2}\n|   |   |-- {library_name}\n...\n```\n\n## Load\n\nUsing jni-generated libraries is very simple, for example you have the following building script:\n\n```scala\nobject libjni extends RustJniModule { // You can also extends PublishModule to publish this library jar to maven central \n\n  override def release: Boolean = true\n\n}\n\nobject jni_jvm_interface extends ScalaModule { // jni_jvm_interface is example module, it can be anything you like.\n  override def scalaVersion = \"3.2.1\"\n\n  // use this to dependent maven central jni module, or other dependencies.\n  // if this module is include jni jvm interface, you can also add a loader helper by this project.\n  override def ivyDeps: T[Loose.Agg[Dep]] = Agg(\n    ivy\"{organization}:{artifactId}:{version}\", // some dependency\n    ivy\"io.github.otavia-projects::jni-loader:{version}\" // loader helper\n  )\n\n  // use this to dependent local jni module dependencies.\n  override def moduleDeps: scala.Seq[JavaModule] = scala.Seq(libjni)\n\n}\n\n\n```\n\nThen define the native methods on the jvm in the jni_jvm_interface module:\n\ndefined by scala\n\n```scala\npackage io.github.example\n\nimport io.github.otavia.jni.loader.NativeLoader\n\nobject RustJNI extends NativeLoader(\"libjni\") {\n  @native def add(a: Int, b: Int): Int\n}\n\n// or in class\n\nclass Adder(val base: Int) extends NativeLoader(\"libjni\") {\n  @native def plus(term: Int): Int\n}\n```\n\ndefined by java\n\n```java\npackage io.github.example;\n\nimport io.github.otavia.jni.loader.NativeLoader;\n\nclass JavaJNI extends NativeLoader {\n    private int base = 0;\n\n    JavaJNI() {\n        super(\"libjni\");\n    }\n\n    public static native int add(int a, int b);\n\n    public native void plus(int term);\n\n}\n\n```\n\nCorrespondingly, the code implemented in the libjni module native/src/lib.rs is\n\n```rust\nuse jni::JNIEnv;\nuse jni::objects::*;\nuse jni::sys::*;\n\n#[no_mangle]\npub unsafe extern \"C\" fn Java_io_github_example_RustJNI_00024_add\u003c'local\u003e(mut env: JNIEnv\u003c'local\u003e, this: JObject\u003c'local\u003e, a: jint, b: jint) -\u003e jint {\n    a + b\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn Java_io_github_example_Adder_plus\u003c'local\u003e(mut env: JNIEnv\u003c'local\u003e, this: JObject\u003c'local\u003e, term: jint) -\u003e jint {\n    todo!()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn Java_io_github_example_JavaJNI_add\u003c'local\u003e(mut env: JNIEnv\u003c'local\u003e, clz: JClass\u003c'local\u003e, a: jint, b: jint) -\u003e jint {\n    todo!()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn Java_io_github_example_JavaJNI_plus\u003c'local\u003e(mut env: JNIEnv\u003c'local\u003e, this: JObject\u003c'local\u003e, term: jint) {\n    todo!()\n}\n\n```\n\n`NativeLoader` uses the environment variable `RUN_RUST_TARGET` to specify the correct runtime rust target, for example\non the author's x86_64 Windows 10 machine\n\n```shell\nRUN_RUST_TARGET=\"x86_64-pc-windows-msvc\"\n```\n\nIf not specified, `NativeLoader` will speculate on possible targets, which may result in not loading the correct library\nfile.\n\n## rust jni method naming rules\n\nThis plugin does not use `javah` to generate C headers, because the corresponding jni method naming rules are very\nsimple:\n\n1. Use the `Java_` prefix for the method name.\n2. Next, use the package name of the class where the native method is located, and convert the dot to an underscore.\n3. Next, use the class name, or in the case of scala object objects, using the object name + `_00024`.\n4. Next is the native method name.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fotavia-projects%2Fmill-rust-jni","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fotavia-projects%2Fmill-rust-jni","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fotavia-projects%2Fmill-rust-jni/lists"}