You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-24 17:56:45 +02:00
Publish Comprehensive Rust 🦀
This commit is contained in:
13
src/android/interoperability/cpp.md
Normal file
13
src/android/interoperability/cpp.md
Normal file
@ -0,0 +1,13 @@
|
||||
# With C++
|
||||
|
||||
The [CXX crate][1] makes it possible to do safe interoperability between Rust
|
||||
and C++.
|
||||
|
||||
The overall approach looks like this:
|
||||
|
||||
<img src="cpp/overview.svg">
|
||||
|
||||
See the [CXX tutorial][2] for an full example of using this.
|
||||
|
||||
[1]: https://cxx.rs/
|
||||
[2]: https://cxx.rs/tutorial.html
|
1
src/android/interoperability/cpp/overview.svg
Symbolic link
1
src/android/interoperability/cpp/overview.svg
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../third_party/cxx/overview.svg
|
39
src/android/interoperability/java.md
Normal file
39
src/android/interoperability/java.md
Normal file
@ -0,0 +1,39 @@
|
||||
# Interoperability with Java
|
||||
|
||||
Java can load shared objects via [Java Native Interface
|
||||
(JNI)](https://en.wikipedia.org/wiki/Java_Native_Interface). The [`jni`
|
||||
crate](https://docs.rs/jni/) allows you to create a compatible library.
|
||||
|
||||
First, we create a Rust function to export to Java:
|
||||
|
||||
_interoperability/java/src/lib.rs_:
|
||||
|
||||
```rust,compile_fail
|
||||
{{#include java/src/lib.rs:hello}}
|
||||
```
|
||||
|
||||
_interoperability/java/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include java/Android.bp:libhello_jni}}
|
||||
```
|
||||
|
||||
Finally, we can call this function from Java:
|
||||
|
||||
_interoperability/java/HelloWorld.java_:
|
||||
|
||||
```java
|
||||
{{#include java/HelloWorld.java:HelloWorld}}
|
||||
```
|
||||
|
||||
_interoperability/java/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include java/Android.bp:helloworld_jni}}
|
||||
```
|
||||
|
||||
Finally, you can build, sync, and run the binary:
|
||||
|
||||
```shell
|
||||
{{#include ../build_all.sh:helloworld_jni}}
|
||||
```
|
17
src/android/interoperability/java/Android.bp
Normal file
17
src/android/interoperability/java/Android.bp
Normal file
@ -0,0 +1,17 @@
|
||||
// ANCHOR: libhello_jni
|
||||
rust_ffi_shared {
|
||||
name: "libhello_jni",
|
||||
crate_name: "hello_jni",
|
||||
srcs: ["src/lib.rs"],
|
||||
rustlibs: ["libjni"],
|
||||
}
|
||||
// ANCHOR_END: libhello_jni
|
||||
|
||||
// ANCHOR: helloworld_jni
|
||||
java_binary {
|
||||
name: "helloworld_jni",
|
||||
srcs: ["HelloWorld.java"],
|
||||
main_class: "HelloWorld",
|
||||
required: ["libhello_jni"],
|
||||
}
|
||||
// ANCHOR_END: helloworld_jni
|
29
src/android/interoperability/java/HelloWorld.java
Normal file
29
src/android/interoperability/java/HelloWorld.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ANCHOR: HelloWorld
|
||||
class HelloWorld {
|
||||
private static native String hello(String name);
|
||||
|
||||
static {
|
||||
System.loadLibrary("hello_jni");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String output = HelloWorld.hello("Alice");
|
||||
System.out.println(output);
|
||||
}
|
||||
}
|
33
src/android/interoperability/java/src/lib.rs
Normal file
33
src/android/interoperability/java/src/lib.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// ANCHOR: hello
|
||||
//! Rust <-> Java FFI demo.
|
||||
|
||||
use jni::objects::{JClass, JString};
|
||||
use jni::sys::jstring;
|
||||
use jni::JNIEnv;
|
||||
|
||||
/// HelloWorld::hello method implementation.
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_HelloWorld_hello(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
name: JString,
|
||||
) -> jstring {
|
||||
let input: String = env.get_string(name).unwrap().into();
|
||||
let greeting = format!("Hello, {input}!");
|
||||
let output = env.new_string(greeting).unwrap();
|
||||
output.into_inner()
|
||||
}
|
26
src/android/interoperability/with-c.md
Normal file
26
src/android/interoperability/with-c.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Interoperability with C
|
||||
|
||||
Rust has full support for linking object files with a C calling convention.
|
||||
Similarly, you can export Rust functions and call them from C.
|
||||
|
||||
You can do it by hand if you want:
|
||||
|
||||
```rust
|
||||
extern "C" {
|
||||
fn abs(x: i32) -> i32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = -42;
|
||||
let abs_x = unsafe { abs(x) };
|
||||
println!("{x}, {abs_x}");
|
||||
}
|
||||
```
|
||||
|
||||
We already saw this in the [Safe FFI Wrapper
|
||||
exercise](../../exercises/day-3/safe-ffi-wrapper.md).
|
||||
|
||||
> This assumes full knowledge of the target platform. Not recommended for
|
||||
> production.
|
||||
|
||||
We will look at better options next.
|
75
src/android/interoperability/with-c/bindgen.md
Normal file
75
src/android/interoperability/with-c/bindgen.md
Normal file
@ -0,0 +1,75 @@
|
||||
# Using Bindgen
|
||||
|
||||
The [bindgen](https://rust-lang.github.io/rust-bindgen/introduction.html) tool
|
||||
can auto-generate bindings from a C header file.
|
||||
|
||||
First create a small C library:
|
||||
|
||||
_interoperability/bindgen/libbirthday.h_:
|
||||
|
||||
```c
|
||||
{{#include bindgen/libbirthday.h:card}}
|
||||
```
|
||||
|
||||
_interoperability/bindgen/libbirthday.c_:
|
||||
|
||||
```c
|
||||
{{#include bindgen/libbirthday.c:print_card}}
|
||||
```
|
||||
|
||||
Add this to your `Android.bp` file:
|
||||
|
||||
_interoperability/bindgen/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include bindgen/Android.bp:libbirthday}}
|
||||
```
|
||||
|
||||
Create a wrapper header file for the library (not strictly needed in this
|
||||
example):
|
||||
|
||||
_interoperability/bindgen/libbirthday_wrapper.h_:
|
||||
|
||||
```c
|
||||
{{#include bindgen/libbirthday_wrapper.h:include}}
|
||||
```
|
||||
|
||||
You can now auto-generate the bindings:
|
||||
|
||||
_interoperability/bindgen/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include bindgen/Android.bp:libbirthday_bindgen}}
|
||||
```
|
||||
|
||||
Finally, we can use the bindings in our Rust program:
|
||||
|
||||
_interoperability/bindgen/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include bindgen/Android.bp:print_birthday_card}}
|
||||
```
|
||||
|
||||
_interoperability/bindgen/main.rs_:
|
||||
|
||||
```rust,compile_fail
|
||||
{{#include bindgen/main.rs:main}}
|
||||
```
|
||||
|
||||
Build, push, and run the binary on your device:
|
||||
|
||||
```shell
|
||||
{{#include ../../build_all.sh:print_birthday_card}}
|
||||
```
|
||||
|
||||
Finally, we can run auto-generated tests to ensure the bindings work:
|
||||
|
||||
_interoperability/bindgen/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include bindgen/Android.bp:libbirthday_bindgen_test}}
|
||||
```
|
||||
|
||||
```shell
|
||||
{{#include ../../build_all.sh:libbirthday_bindgen_test}}
|
||||
```
|
36
src/android/interoperability/with-c/bindgen/Android.bp
Normal file
36
src/android/interoperability/with-c/bindgen/Android.bp
Normal file
@ -0,0 +1,36 @@
|
||||
// ANCHOR: libbirthday
|
||||
cc_library {
|
||||
name: "libbirthday",
|
||||
srcs: ["libbirthday.c"],
|
||||
}
|
||||
// ANCHOR_END: libbirthday
|
||||
|
||||
// ANCHOR: libbirthday_bindgen
|
||||
rust_bindgen {
|
||||
name: "libbirthday_bindgen",
|
||||
crate_name: "birthday_bindgen",
|
||||
wrapper_src: "libbirthday_wrapper.h",
|
||||
source_stem: "bindings",
|
||||
static_libs: ["libbirthday"],
|
||||
}
|
||||
// ANCHOR_END: libbirthday_bindgen
|
||||
|
||||
// ANCHOR: libbirthday_bindgen_test
|
||||
rust_test {
|
||||
name: "libbirthday_bindgen_test",
|
||||
srcs: [":libbirthday_bindgen"],
|
||||
crate_name: "libbirthday_bindgen_test",
|
||||
test_suites: ["general-tests"],
|
||||
auto_gen_config: true,
|
||||
clippy_lints: "none", // Generated file, skip linting
|
||||
lints: "none",
|
||||
}
|
||||
// ANCHOR_END: libbirthday_bindgen_test
|
||||
|
||||
// ANCHOR: print_birthday_card
|
||||
rust_binary {
|
||||
name: "print_birthday_card",
|
||||
srcs: ["main.rs"],
|
||||
rustlibs: ["libbirthday_bindgen"],
|
||||
}
|
||||
// ANCHOR_END: print_birthday_card
|
20
src/android/interoperability/with-c/bindgen/c-library.md
Normal file
20
src/android/interoperability/with-c/bindgen/c-library.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Create a C library
|
||||
|
||||
_interoperability/c/libbirthday/Android.bp_:
|
||||
|
||||
```javascript
|
||||
{{#include c/libbirthday/Android.bp:libbirthday}}
|
||||
```
|
||||
|
||||
_interoperability/c/libbirthday/libbirthday.h_:
|
||||
|
||||
```c
|
||||
{{#include c/libbirthday/libbirthday.h}}
|
||||
```
|
||||
|
||||
_interoperability/c/libbirthday/libbirthday.c_:
|
||||
|
||||
```c
|
||||
{{#include c/libbirthday/libbirthday.c}}
|
||||
```
|
||||
|
26
src/android/interoperability/with-c/bindgen/libbirthday.c
Normal file
26
src/android/interoperability/with-c/bindgen/libbirthday.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ANCHOR: print_card
|
||||
#include <stdio.h>
|
||||
#include "libbirthday.h"
|
||||
|
||||
void print_card(const card* card) {
|
||||
printf("+--------------\n");
|
||||
printf("| Happy Birthday %s!\n", card->name);
|
||||
printf("| Congratulations with the %i years!\n", card->years);
|
||||
printf("+--------------\n");
|
||||
}
|
23
src/android/interoperability/with-c/bindgen/libbirthday.h
Normal file
23
src/android/interoperability/with-c/bindgen/libbirthday.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ANCHOR: card
|
||||
typedef struct card {
|
||||
const char* name;
|
||||
int years;
|
||||
} card;
|
||||
|
||||
void print_card(const card* card);
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ANCHOR: include
|
||||
#include "libbirthday.h"
|
29
src/android/interoperability/with-c/bindgen/main.rs
Normal file
29
src/android/interoperability/with-c/bindgen/main.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// ANCHOR: main
|
||||
//! Bindgen demo.
|
||||
|
||||
use birthday_bindgen::{card, print_card};
|
||||
|
||||
fn main() {
|
||||
let name = std::ffi::CString::new("Peter").unwrap();
|
||||
let card = card {
|
||||
name: name.as_ptr(),
|
||||
years: 42,
|
||||
};
|
||||
unsafe {
|
||||
print_card(&card as *const card);
|
||||
}
|
||||
}
|
1
src/android/interoperability/with-c/calling-rust.md
Normal file
1
src/android/interoperability/with-c/calling-rust.md
Normal file
@ -0,0 +1 @@
|
||||
# Calling Rust from C
|
21
src/android/interoperability/with-c/hand-written.md
Normal file
21
src/android/interoperability/with-c/hand-written.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Handwritten FFI
|
||||
|
||||
We can declare external functions by hand:
|
||||
|
||||
```rust
|
||||
extern "C" {
|
||||
fn abs(x: i32) -> i32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = -42;
|
||||
let abs_x = unsafe { abs(x) };
|
||||
println!("{x}, {abs_x}");
|
||||
}
|
||||
```
|
||||
|
||||
We already saw this in the [Safe FFI Wrapper
|
||||
exercise](../../exercises/day-3/safe-ffi-wrapper.md).
|
||||
|
||||
> This assumes full knowledge of the target platform. Not recommended for
|
||||
> production.
|
42
src/android/interoperability/with-c/rust.md
Normal file
42
src/android/interoperability/with-c/rust.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Calling Rust
|
||||
|
||||
Exporting Rust functions and types to C is easy:
|
||||
|
||||
_interoperability/rust/libanalyze/analyze.rs_
|
||||
|
||||
```rust,editable
|
||||
{{#include rust/libanalyze/analyze.rs:analyze_numbers}}
|
||||
```
|
||||
|
||||
_interoperability/rust/libanalyze/analyze.h_
|
||||
|
||||
```c
|
||||
{{#include rust/libanalyze/analyze.h:analyze_numbers}}
|
||||
```
|
||||
|
||||
_interoperability/rust/libanalyze/Android.bp_
|
||||
|
||||
```javascript
|
||||
{{#include rust/libanalyze/Android.bp}}
|
||||
```
|
||||
|
||||
We can now call this from a C binary:
|
||||
|
||||
_interoperability/rust/analyze/main.c_
|
||||
|
||||
```c
|
||||
{{#include rust/analyze/main.c:main}}
|
||||
```
|
||||
|
||||
_interoperability/rust/analyze/Android.bp_
|
||||
|
||||
```javascript
|
||||
{{#include rust/analyze/Android.bp}}
|
||||
```
|
||||
|
||||
|
||||
Build, push, and run the binary on your device:
|
||||
|
||||
```shell
|
||||
{{#include ../../build_all.sh:analyze_numbers}}
|
||||
```
|
@ -0,0 +1,5 @@
|
||||
cc_binary {
|
||||
name: "analyze_numbers",
|
||||
srcs: ["main.c"],
|
||||
static_libs: ["libanalyze_ffi"],
|
||||
}
|
24
src/android/interoperability/with-c/rust/analyze/main.c
Normal file
24
src/android/interoperability/with-c/rust/analyze/main.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ANCHOR: main
|
||||
#include "analyze.h"
|
||||
|
||||
int main() {
|
||||
analyze_numbers(10, 20);
|
||||
analyze_numbers(123, 123);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
rust_ffi {
|
||||
name: "libanalyze_ffi",
|
||||
crate_name: "analyze_ffi",
|
||||
srcs: ["analyze.rs"],
|
||||
include_dirs: ["."],
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ANCHOR: analyze_numbers
|
||||
#ifndef ANALYSE_H
|
||||
#define ANALYSE_H
|
||||
|
||||
extern "C" {
|
||||
void analyze_numbers(int x, int y);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// ANCHOR: analyze_numbers
|
||||
//! Rust FFI demo.
|
||||
#![deny(improper_ctypes_definitions)]
|
||||
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Analyze the numbers.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn analyze_numbers(x: c_int, y: c_int) {
|
||||
if x < y {
|
||||
println!("x ({x}) is smallest!");
|
||||
} else {
|
||||
println!("y ({y}) is probably larger than x ({x})");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user