Basic Android Toodle app + Rust JNA bindings#30
Conversation
fluffyemily
left a comment
There was a problem hiding this comment.
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.
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.
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 |
fluffyemily
left a comment
There was a problem hiding this comment.
Just a few concerns about calling unsafe code from inside ListManager.
complex/cargo/ffi-utils/src/lib.rs
Outdated
| r_str.to_string() | ||
| } | ||
|
|
||
| pub fn to_string(pointer: *const c_char) -> String { |
There was a problem hiding this comment.
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
| let _ = Box::from_raw(item); | ||
| } | ||
|
|
||
| // TODO Can these simpler android methods also work for swift? |
There was a problem hiding this comment.
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.
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.
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
|
|
||
| #[no_mangle] | ||
| pub unsafe extern "C" fn a_label_destroy(_: Box<Label>) { | ||
| // magic! |
There was a problem hiding this comment.
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.
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.
| } | ||
| } | ||
|
|
||
| pub fn fetch_item_uuids(&self) -> Vec<*const c_char> { |
There was a problem hiding this comment.
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.
Ah, good call! I'll revise this.
complex/cargo/list/src/items.rs
Outdated
|
|
||
| #[repr(C)] | ||
| #[derive(Debug)] | ||
| pub struct ItemJNA { |
There was a problem hiding this comment.
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.
| uuids | ||
| } | ||
|
|
||
| pub fn fetch_all_items(&self) -> Vec<ItemJNA> { |
There was a problem hiding this comment.
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 Boxing it for return.
There was a problem hiding this comment.
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_dateandcompletion_date