SwiftAndroid / swift

Port of Apple's reference Swift toolchain to Android; doesn't quite work yet

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

libicu doesn't link at runtime on android systems with their own icu

ephemer opened this issue · comments

I have been playing around with the JNI from within Android Studio and got my first direct Java->Swift->Java call working in a normal APK.

The problem I ran into is that libicu doesn't seem to load in the same way al the other libraries do. I repeatedly get a libswiftCore couldn't load because it couldn't find a certain libicu symbol (which I established is in libicui18n.so). Putting libicui18n.so in the system /lib directory gets the app running, but this requires the device to be rooted as far as I understand (I'd never heard of Android Studio let alone the JNI a month ago, bear with me).

I was wondering whether we can statically (instead of dynamically) link libicu for libswiftCore, and whether this may solve the problem of needing to link it at runtime (which apparently doesn't work). Who knows, maybe I'm just overlooking something, but I found the experience of manually setting all the shared libraries to load kind of painful overall. I also wonder if we can save on overall binary size with static linking? Excuse the noob questions, I'm new to this whole world but learning fast...

It's probably possible, but since you have Java can't you just System.loadLibrary libicu directly?

Also, don't worry: I'm more noob here than you are (never compiled LLVM - or indeed wrote any Swift - before this project)

Hmm, I didn't try that yet, because I don't need to System.loadLibrary on libswiftCore or any of the others for my SwiftTest library to load correctly. Just including the other .sos in Android.mk seems to be enough to make them available at runtime. This didn't seem to work for libicu for some reason. I'm not sure if it's worth posting about this on the mailing list because it's very specific to the SwiftAndroid port, but I will if I can't figure out something else.

Well you seem to know your way around compiling and linking a lot more than I do, I do have a fair bit of experience with Swift though, so it seems like a good combination so far. Out of interest, are you still working on anything for this project at the moment?

I'll have more time next week to work on it: the next thing I would like to do is to clean it up enough to send a pull request upstream. Later I would like to add some sort of Android Studio/Gradle integration but I need to learn Gradle first.

As a direct response to using System.loadLibrary: it doesn't seem to work. I've also tried using absolute paths via System.load(/absolute/path/to/libicudata.so, icui18n and icuuc) to be sure the newly-compiled ICU is used instead of the outdated inbuilt version. The missing symbols remain unresolved.

I am looking at this again, it seems to be the only hurdle before getting Android APKs working on a device.

The only solution that I can see working at this stage is to build ICU with essentially a different SONAME so that it can be linked against specifically (and without needing RPATH). Today I tried to change ICUPREFIX from icu to swiftICU in the following files

icu/source/icudefs.mk.in
icu/source/config/Makefile.inc.in

But the output files are still named libicuXX.so, and readelf -d doesn't show any SONAME at all, so my change didn't seem to do anything. I keep running up against this issue with these build systems- I change something and nothing happens! Makes it hard for me to figure out what's going on.

@zhuowei do you have an idea how to change the effective SONAME and/or just the file names when building ICU?

Apparently SONAME is ignored at runtime anyway, so we do need to link icu internally with the different names as well (ie. libswiftICUxx.so). If we don't, e.g. libswiftICUi18n.so will link correctly from Swift, but then i18n will try to link against the Android-included libicuuc.so, so we'd be back at square one.

I couldn't figure out how to compile ICU differently yet, but I did a hacky solution as per https://groups.google.com/forum/#!msg/android-ndk/_UhNpRJlA1k/7_R6NwhiKa0J changing libicu to libscu in all instances of the .so files, including in the Swift libraries of course. It works! So we have swift-powered APKs running on a device. There's some work to be done in getting this setup repeatable though.

@zhuowei do you consider it a viable longer-term solution to compile icu with a different SONAME e.g. libscuXX.so and linking those? As far as I see there's no more reliable option for dynamic linking on Android

edit: for future reference, replace the dependency names in the .so files via:
rpl -R -e libicu libscu libswift*.so

I think I figured out the issue: the libicu wasn't being compiled correctly on my end (it's still compiled with gnustl instead of libc++). I pushed the fix; after rebuilding the new libicu is able to run on Nexus 6P correctly in an APK.

https://github.com/SwiftAndroid/libiconv-libicu-android

I'm going to close this out, since it seems like this issue was resolved. 👍

@modocache I'm still using the weird workaround, i.e. manually replacing strings in the libicu binaries. My memory of it was that that recompiling libicu with the other c++ stdlib didn't have any effect here. Just want to confirm it was really fixed

Hmm, interesting. I've simply been running the Swift test suites on device, so I'm not sure about running APKs... if this is still an issue definitely feel free to re-open it!

Alright, I'm not working with android actively at the moment but if it
comes up again I'll reopen the issue

@modocache I'm pretty certain this is still an issue. We are now running into an issue even loading libc++_shared.so on Android < 4.3 when Crosswalk v18+ is also installed. I assume the reason is that Crosswalk v18 loads its own incompatible version of libc++_shared.so, which means even if we explicitly called System.loadLibrary on ours (that Swift needs), the other one is already loaded and ours is ignored.

I'm reopening this, because the workaround presented (rpl -R -e libicu libscu libswift*.so) is still relevant and required until we can come up with a better solution

I'd say any major issue should be reported on Swift JIRA. That way, we could get input from a broader set of people familiar with Swift.