Libicu in custom location

A Kotbase user asked about how to ensure their app can provide the required libicu version for users running their app on Linux, if they don’t have the required library version installed already. This is using the CBL Java SDK running in the JVM on Linux.

I looked into where the libicu library is loaded in CBL Core and see that it seems to check the CBL_ICU_LOCATION environment variable before defaulting to /usr/lib/<arch_folder>. I tested setting this CBL_ICU_LOCATION environment variable to a custom path, e.g. /home/jeff/Desktop/libicu, and temporarily moving libicu*.so.71* from /usr/lib/x86_64-linux-gnu to that location, but the app crashes with a linker error unless the library is found in /usr/lib/x86_64-linux-gnu.

Caused by: java.lang.UnsatisfiedLinkError: …/libLiteCore.so: libicuuc.so.71: cannot open shared object file: No such file or directory

Am I missing something with how the code works here? Is there a preferred mechanism for apps to be able to provide the libicu dependency at runtime?

We provide a bundle: couchbase-lite-java-linux-supportlibs-X.Y.Z.zip that contains the libicu lib (we want to use the one with which LiteCore was built).
Normally, you expand that zip-file and add the path to it, to LD_LIBRARY_PATH.
The JVM should set its system property “java.library.path” from the shell var.

Very keen observation by the way to find the environment variables. I wrote that code in question and I can tell you why it won’t work for you. You’ll notice a define in the file called CBL_USES_ICU_SHIM. This won’t be true for Java, so all of that logic is compiled out. That logic is for C so that it doesn’t have to take a dependency at compile time on ICU and can instead have a package level (apt) dependency, in which we are unsure which version we are getting.

Java expects you to have preinstall this and other libraries, and I can refer you to our documentation page about it. I think it has the exact answer to your question.

Thanks, this makes sense now why the CBL_ICU_LOCATION environment variable does appear to work when running Kotbase on native Linux, which uses the C SDK.

It looks like setting java.library.path at runtime doesn’t work. It’s probably caching the original value.

// doesn't work
System.setProperty("java.library.path", "${System.getProperty("java.library.path")}:/my/lib/path")

Setting the LD_LIBRARY_PATH does work, as documented in the .bashrc or .profile file. How to set the variable specifically for the executing Java app probably depends how the app is being packaged and distributed. It could be done from a bash script launcher, for example:

#!/bin/bash
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/my/lib/path"
java -jar yourApp.jar

I’m actually finding (and so is the user) that even setting java.library.path as a JVM arg when running the app, that it doesn’t find the library on the path added to the property. So is it getting the paths from the LD_LIBRARY_PATH environment variable directly? Is that the only way to specify the library path?

This is not Core behavior any more at this point. This is standard GNU ld linking. In the absence of ICU shim, LiteCore is compiled with a hard dependency on libicu version 71. Finding it is a function of the dynamic linker on Linux and follows the dynamic linker rules (which java.library.path and LD_LIBRARY_PATH are designed to influence).

It looks like java.library.path is used to locate the initial library loaded with System.loadLibrary. But only LD_LIBRARY_PATH is used to resolve dependencies of that library. This is good to know. It might be helpful to update the docs to clarify this. Thanks for your help.

If that is true, it is news to me. I will, most definitely, have a look.
My understanding was that the JVM only used java.library.path and that it, typically, got that from the LD_LIBRARY_PATH env var.
… and, as Jim pointed out, none of this has anything to do with LiteCore. It is all on the JVM.

Created https://jira.issues.couchbase.com/browse/CBL-6980 to track this.

Great, I’ll be interested to see what your findings are. It certainly seems easier if this path can be provided as a JVM arg, rather than needing to be a system environment variable.