Bazel: prevent android_binary from creating new jni layer - android

I have an Android app that uses a java API that wraps a C native lib. I have this working: android_binary (name: "MyLibTest") depends on the API, which is built as android_library (name: "MyLibAndroid") with a dependency on the jni layer (cc_library, name: "mylib_jni"), which depends on the wrapped C lib (cc_library, name "mylib").
I want MyLibAndroid to be responsible for loading the native code using System.loadLibrary("mylib_jni"). The problem is that Bazel is creating a native library for my android_binary app, so instead I have to put System.loadLibrary("MyLibTest") in my app code.
Is there a way to tell Bazel to associate the native jni lib with the android_library rather than the android_binary?

The reason that bazel names the .so the same as the android_binary is that bazel links all the cc_library rules in the dependencies of the android_binary into a single .so file, so it doesn't really work to pick one of the names of the cc_library rules.
One way to handle this is to read the file named nativedeps that Bazel puts at the root of the apk. It will contain the name of the .so file that bazel linked, so you don't have to hardcode the name in your library code.

Related

Java.Lang.UnsatisfiedLinkError: 'No implementation found for

I'm trying to use OpenCv 4 on Xamarin.Android by Java Binding Template. These are the steps that i've done:
0) I've compiled opencv binaries through cmake and mingw64 to get .jar and .a
I've put the .jar and the static libraries (.a) in Jars forlder of Xamarin Java Binding Template and i've compiled the template.
1.a) .jar Build Action is EmbeddedJar
1.b) libs Build Action is EmbeddedNativeLibrary
I've added a reference to that template in my Xamarin.Android project: the opencv methods were recognized correctly!
But, when i try to execute:
Mat Source = Imgcodecs.Imread(ImagePath, Imgcodecs.ImreadGrayscale);
i get an error:
Java.Lang.UnsatisfiedLinkError: 'No implementation found for long org.opencv.imgcodecs.Imgcodecs.imread_0(java.lang.String, int) (tried Java_org_opencv_imgcodecs_Imgcodecs_imread_10 and Java_org_opencv_imgcodecs_Imgcodecs_imread_10__Ljava_lang_String_2I)'
I think that there could be a missmatch of method name, maybe due to a wrong java parsing.
I've also tried to use shared libries (.so) by loading them through JavaSystem.LoadLibrary("LibraryNameWithoutInitialLib"), but i have the same error :/
Do you know why?
You cannot link static libraries with Xamarin.Android as the Xamarin/Mono NDK-based runtime is a static main entry executable and does not dynamically get built per project. If you do not need to use a .jar/.aar high-level wrapper, then you will need to use runtime shared libraries and define DllImportAttribute entries for the exported functions that you need to call.
Xamarin.Android supports the use of native libraries via the standard PInvoke mechanism.
Using Native Libraries
Use C/C++ libraries with Xamarin
Note: There are numerous OpenCV C# wrappers / DllImport files in open source ( i.e. a github search away 😁)
Note: If you are using a 3rd-party .jar/.aar , make sure that they are using OpenCV shared libraries and thus not requiring a gradle script to link them into an NDK-based Android app.

Equivalent of 'compileOnly' in Android.mk

I have a pre-built java library as a compile time dependency for Android library project(AAR). So while building it in Android Studio, 'compileOnly' is used so that the same gets linked in runtime when deployed with an APK.
However, I should also write an equivalent Android.mk for the library project. I am not able to find any reference to include a prebuilt java library in Android.mk. Can someone help me on this part.
I tried using LOCAL_PREBUILT_JAVA_LIBRARIES attribute, but the system threw an error:
error: dont use LOCAL_PREBUILT_JAVA_LIBRARIES anymore LOCAL_PATH=xxx.
This kind of dependency linking may look strange. Let me give some insight into it also. Basically I am building an application that has one small part being developed by a third party. The setter interface APIs for the third party are shipped in by me in the form of a .jar file so that they use the same as a compile time dependency and build an AAR out of it.
Now the third party project is to be included in my project build(AOSP). This brings a dependency that their module should be compiled for the AAR to get generated and my project uses that AAR to generate the APK.
For the AAR to get compiled and built, I need to link the prebuilt java interface library that is shipped in by me(mentioned in the first step).
Need an equivalent of 'compileOnly' used in build.gradle.

How to link against a shared library without inclusion in final package?

I have been working with a project that needs to link against two shared libraries from other applications, without actually including them in the final package. I was using Android Studio with a common way of executing an external ndk-build but I am now using the experimental gradle NDK support.
From what I understand from the information here, using the jniLibs source set will package the binary with the final application, which is not what I want. I would like to link against the libraries during compile time, and expect that my own module is loaded in an environment where they are available.
My old workaround was to add the line: TARGET_NO_UNDEFINED_LDFLAGS := within the Android.mk, but I'm not aware of any way to something equivalent with the new NDK support.
Currently, I am including the jni directory which contains the libraries alongside my source by adding -L"<directory>" to ldFlags, and linking against them as I would with a system library, as below (currently, I am only building for ARMv7):
android.ndk {
moduleName = "ropecraftpe"
ldLibs.addAll(['log', 'name of one library', 'name of other library'])
ldFlags.add('-L"' + file('src/main/jni').absolutePath + '"')
cppFlags.add('-std=c++11')
stl = 'gnustl_shared'
abiFilters.addAll(['armeabi-v7a'])
}
This works for the most part - oddly enough, the linker does not complain about calls to static functions or globals, but does complain when attempting to use a constructor defined in one of the libraries: Error:(12) undefined reference to 'ClassName::ClassName(std::string const&, etc.)'. This class is defined in a header file included from my own C++ code, and the constructor is definitely present in the linked .so.
How does one go about linking this project successfully?
I have made a workaround; my solution was to add the libraries that I wished to link against to the NDK's system library directory.
This is located under ANDROID_NDK/platforms/android-XX/arch-XX/usr/lib/. This appears to work fine, as I wanted the libraries to be treated in the same way as system libraries (not included as prebuilts, but still linked against).
As an addition, one can place the header files under the include directory there.

How to compile c code in Android project without header-file?

I have a library with c code, and I want to compile it to a .so lib with NDK, but when I run ndk-build command, it needs header file and there is no header file in that library, only dot c.
There are so many source files, and how can I achieve this with it?
Is there a way to compile it without header-file?
Or maybe generate them in batches?
Thanks
You cannot compile a c/cpp file without having access to the header files it requires. Some default header files are usually provided by the corresponding stdlibc which ships with the compiler you use. Others you have to provide yourself by installing their libraries in appropriate paths or giving their path explicitly during compilation.
Generally header files are included by the pre-processor, prior to compilation, as they provide some functionality which is required by the code within the c file (except when they are pointless includes).

Using prebuilt shared library (.so) in new project Android

How I can do this without compile again the native code and all stuff?
It seems like you are probably doing jni to this library. If that is the case, the java package and class name needs to be encoded in the names of the jni functions, so you would have to do something such as:
Always keep the same name for the java package and class file which actually interfaces to the native library. This does not need to match the main package name for the APK. You may want to make this a sort of wrapper for the native library.
Or you could create a new native library using the new package name which is just a wrapper calling the original library by it's original function names. This will be a bit more complicated to set up than the previous idea.
Create libs/<arch> folder, and put the so file there. Eclipse or ant build system will automatically pick it up and package in apk file.
In place of <arch> use one of armeabi, armeabi-v7a, x86 or mips - depending on how .so file has been built.

Categories

Resources