-
Notifications
You must be signed in to change notification settings - Fork 35
Basic Android Toodle app + Rust JNA bindings #30
base: master
Are you sure you want to change the base?
Conversation
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've been trying to compile this but when I come to building the android lib I get the following error:
cargo build --target i686-linux-android --release
Compiling libsqlite3-sys v0.8.1
error: failed to run custom build command for `libsqlite3-sys v0.8.1`
process didn't exit successfully: `/Users/emilytoop/Development/cross-platform-rust/complex/cargo/target/release/build/libsqlite3-sys-af5f505c0fc46472/build-script-build` (exit code: 101)
--- stdout
TARGET = Some("i686-linux-android")
OPT_LEVEL = Some("3")
TARGET = Some("i686-linux-android")
HOST = Some("x86_64-apple-darwin")
TARGET = Some("i686-linux-android")
TARGET = Some("i686-linux-android")
HOST = Some("x86_64-apple-darwin")
CC_i686-linux-android = None
CC_i686_linux_android = None
TARGET_CC = None
CC = None
TARGET = Some("i686-linux-android")
HOST = Some("x86_64-apple-darwin")
CFLAGS_i686-linux-android = None
CFLAGS_i686_linux_android = None
TARGET_CFLAGS = None
CFLAGS = None
DEBUG = Some("false")
running: "i686-linux-android-gcc" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m32" "-DSQLITE_CORE" "-DSQLITE_DEFAULT_FOREIGN_KEYS=1" "-DSQLITE_ENABLE_API_ARMOR" "-DSQLITE_ENABLE_COLUMN_METADATA" "-DSQLITE_ENABLE_DBSTAT_VTAB" "-DSQLITE_ENABLE_FTS3" "-DSQLITE_ENABLE_FTS3_PARENTHESIS" "-DSQLITE_ENABLE_FTS5" "-DSQLITE_ENABLE_JSON1" "-DSQLITE_ENABLE_LOAD_EXTENSION=1" "-DSQLITE_ENABLE_MEMORY_MANAGEMENT" "-DSQLITE_ENABLE_RTREE" "-DSQLITE_ENABLE_STAT2" "-DSQLITE_ENABLE_STAT4" "-DSQLITE_HAVE_ISNAN" "-DSQLITE_SOUNDEX" "-DSQLITE_THREADSAFE=1" "-DSQLITE_USE_URI" "-DHAVE_USLEEP=1" "-Wall" "-Wextra" "-o" "/Users/emilytoop/Development/cross-platform-rust/complex/cargo/target/i686-linux-android/release/build/libsqlite3-sys-9c6be82b1e4f932e/out/sqlite3/sqlite3.o" "-c" "sqlite3/sqlite3.c"
--- stderr
thread 'main' panicked at '
Internal error occurred: Failed to find tool. Is `i686-linux-android-gcc` installed?
I've updated my Android Studio, my NDK and my build tools to try and resolve this, but it looks as if it's a problem with one of our dependencies. Did you encounter this? And if you did, how did you solve it?
complex/cargo/src/lib.rs
Outdated
|
||
#[no_mangle] | ||
pub unsafe extern fn Java_com_mozilla_toodle_RustToodle_newToodle(env: JNIEnv, _: JClass, db_path: JString) -> jlong { | ||
log("newToodle!"); |
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.
Why not just pass the args into the existing new_toodle
function to save having to replicate code? I think the fewer places we have to make changes the better.
complex/cargo/list/src/items.rs
Outdated
|
||
#[no_mangle] | ||
pub unsafe extern fn Java_com_mozilla_toodle_RustToodle_itemSetDueDate(env: JNIEnv, _: JClass, item: *mut Item, due_date: JValue) { | ||
let item = &mut*item; |
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.
again, just call item_set_due_date
rather than having to do it all again here.
@fluffyemily for the build issue, I had to add the NDK/bin directories into my PATH. I'm not sure why, this isn't what I'd expect to have to do (why doesn't .cargo/config work?). Also, a side-effect is that doing so breaks a regular Firefox build, for me anyway (but that's easily remedied by adjusting your PATH again). |
@fluffyemily check out a basic JNA integration. |
It all changed, need another review.
This really needs a rebase on top of @fluffyemily's |
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.
Just a few concerns about calling unsafe code from inside ListManager
.
complex/cargo/ffi-utils/src/lib.rs
Outdated
@@ -24,6 +25,11 @@ pub mod strings { | |||
r_str.to_string() | |||
} | |||
|
|||
pub fn to_string(pointer: *const c_char) -> String { |
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 is exactly the same as c_char_to_string
. Either overwrite the old one or update it to this. No point having 2 functions doing exactly the same thing,
complex/cargo/list/src/items.rs
Outdated
@@ -61,6 +62,16 @@ pub unsafe extern "C" fn item_destroy(item: *mut Item) { | |||
let _ = Box::from_raw(item); | |||
} | |||
|
|||
// TODO Can these simpler android methods also work for swift? |
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.
yes, they can. Let's all use the same FFI if possible.
complex/cargo/list/src/items.rs
Outdated
} | ||
|
||
pub extern "C" fn a_item_destroy(_: Box<Item>) { | ||
// Rust will clean up for us automatically, since we own the Item. |
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 is not the case for iOS so we need to leave a destroy function around for that.
complex/cargo/list/src/items.rs
Outdated
} | ||
|
||
#[no_mangle] | ||
pub unsafe extern "C" fn a_item_set_due_date(item: &mut Item, due_date: *const size_t) { |
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 is essentially the same code. How about we call a_item_set_due_date after casting the *mut Item
pointer to a reference in item_set_due_date
.
complex/cargo/list/src/labels.rs
Outdated
@@ -34,6 +34,11 @@ pub unsafe extern "C" fn label_destroy(label: *mut Label) { | |||
let _ = Box::from_raw(label); | |||
} | |||
|
|||
#[no_mangle] | |||
pub unsafe extern "C" fn a_label_destroy(_: Box<Label>) { | |||
// magic! |
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.
There are compiler flags for different architectures. #[cfg(target_os="android")]
will compile a function just for Android, for example. For functions that have to be different between iOS and Android we should use these flags to ensure not everything is compiled every time and move as much shared code as possible into functions that these architecture specific ones can call into.
complex/cargo/list/src/lib.rs
Outdated
use time::Timespec; | ||
|
||
#[no_mangle] | ||
pub unsafe extern "C" fn a_list_manager_create_item(manager: *const Arc<ListManager>, name: *const c_char, due_date: *const time_t) { |
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.
At this point the iOS app is broken already so I don't mind if you make a breaking change, as long as you check with Kit first to make sure he's not relying on it.
@@ -204,6 +207,23 @@ impl ListManager { | |||
} | |||
} | |||
|
|||
pub fn fetch_item_uuids(&self) -> Vec<*const c_char> { |
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 am not a huge fan of c types being used inside ListManager
. string_to_c_char
calls unsafe code and unsafe code should be kept to the FFI boundary as much as possible which allows this function to be called from elsewhere in Rust without safety worries.
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.
Ah, good call! I'll revise this.
complex/cargo/list/src/items.rs
Outdated
@@ -32,6 +33,15 @@ pub struct Item { | |||
pub labels: Vec<Label>, | |||
} | |||
|
|||
#[repr(C)] | |||
#[derive(Debug)] | |||
pub struct ItemJNA { |
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 is something I have been considering doing for all objects we pass over the boundary - converting them from complex Rust types to C structs. This would also make handling the objects in Swift much easier.
complex/cargo/list/src/lib.rs
Outdated
@@ -224,6 +225,44 @@ impl ListManager { | |||
uuids | |||
} | |||
|
|||
pub fn fetch_all_items(&self) -> Vec<ItemJNA> { |
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.
Take a look at the Into
trait. https://doc.rust-lang.org/std/convert/trait.Into.html
This is a trait you can implement on structs to convert one thing into another. Think about implementing Into for Item
to ItemJNA
and Vec<Item>
to Vec<ItemJNA>
. That way the ListManager
function can deal entirely with safe types and code and you can call list.into()
from inside your FFI function when Box
ing it for return.
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.
What's nice about Into
is that implementing Into
automatically implements From
which means when we pass an ItemJNA
back into we can call item.from()
to turn it back into an Item
.
PR state as of 29/12/17 PST:
TODO:
due_date
andcompletion_date