I'm currently trying to compile OpenCV using Gradle and integrate it within my Android project, but I'm facing an issue and I don't know how to resolve it.
I have created a native library module within my project and created a few gradle tasks for downloading and unzipping the source code within the project. Then, using the CMakeLists.txt file provided in the OpenCV project, I import it using "add_subdirectory" within my application CMakeList.txt file.
With this, the OpenCV compilation complete correctly and generates the two required libraries, libopencv_core.so and libopencv_imgproc.so in the .cxx/RELEASE/buildHash/arm64-v8a/opencv/lib/arm64-v8a/ folder
However, only my own application .so library and the libopencv_imgproc.so are included in the final .aar file. The libopencv_core.so is missing. If I check in the Gradle build folder, located in build/intermediates/cxx/RELEASE/buildHash/obj/arm64-v8a/, I can see the same issue as in the .aar.
The funny thing is, if I only require to use the libopencv_core.so, it will be integrated within the final .aar correctly, and I don't understand why.
Here is my CMakeList.txt file:
cmake_minimum_required(VERSION 3.18.1)
project("myapp")
add_library(
myapp
SHARED
myapp.cpp )
find_library(
log-lib
log )
# OpenCV source code and CMakeList.txt are located in the opencv folder
add_subdirectory(opencv)
# Library opencv_core and opencv_imgproc are generated by the OpenCV CMakeList.txt
target_link_libraries(myapp opencv_core opencv_imgproc ${log-lib} )
target_include_directories(myapp PUBLIC
opencv/modules/core/include
opencv/modules/imgproc/include
)
include_directories (${CMAKE_BINARY_DIR})
My question is, what am I missing ? Is there something I must specify to force the inclusion of the libopencv_core.so ?
PS: Why I'm not simply integrating the binaries instead of compiling them ? Because the app is targeted for F-Droid, which requires to whole code to be compiled from the sources, so this is not an option for me.
I have finally managed to copy the libopencv_core.so in the correct folder and generate a complete aar.
I just had to add the following to my application CMakeLists.txt:
set_target_properties( opencv_core PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} )
I don't really get why I must add this line, but it's working !
Related
For incorporating other opensource libs via CMake, I've checked similar questions such as this one:
Android Studio: Adding a library outside of the project root
but those are about incorporating Android-Studio lib projects instead of external libs.
In my case, I have a folder structure like this:
thirdparty
category
MyLib
src
MyAndroidStudioProject
build.gradle
settings.gradle
...
app
build
libs
src
build.gradle
...
In the project CMakeLists.txt, I then added this
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} MyLib)
set (MyLib_DIR ../../../thirdparty/category/MyLib)
# output lib binary
add_subdirectory (${MyLib_DIR} ./MyLib)
include_directories (${OBOE_DIR}/include)
I learned from sample code and assume that the CMake source root is at src/MyAndroidStudioProject/app, so MyLib is located using relative path accordingly.
However, building the project gives me
CMake Error at /path/to/src/MyAndroidStudioProject/app/src/main/cpp/CMakeLists.txt:53 (add_subdirectory):
add_subdirectory given source "../../../thirdparty/category/MyLib"
which is not an existing directory.
How should I fix this? Should I configure other settings in the project?
OK, solved it myself.
The relative path should be relative to the CMakeLists.txt file, located at
/path/to/src/MyAndroidStudioProject/app/src/main/cpp/CMakeLists.txt
So the correct relative path in my case should be
set (MyLib_DIR ../../../../../../thirdparty/category/MyLib)
i.e., CMakeLists.txt is 3 levels down the app folder.
I've an android app written in Android Studio 3.0.1 and with compileSdkVersion 26. This app depends on a module written in native code (c++). The native code in the module depends on a third party shared library (.so) file. In the Cmake file this third party library is included using the standard method, e.g:
add_library( my-module-lib
SHARED
src/main/cpp/file1.cpp
src/main/cpp/file2.cpp )
add_library( libthird_party_library SHARED IMPORTED )
set_target_properties( libthird_party_library PROPERTIES IMPORTED_LOCATION ${pathToProject}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_library.so)
target_link_libraries( my-module-lib libthird_party_library )
My module is then added as dependency to the main app and the native code is loaded using:
System.loadLibrary("my-module-lib");
This all works fine, however I need to update the third party library. I thought this was just as simple as replacing the old .so files for the new ones. But this leads to an UnsatisfiedLinkError:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libthird_party_library.so.2" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:989)
at java.lang.System.loadLibrary(System.java:1567)
It should be noted that android now searches for a ".so.2" file instead of a ".so" file. So I would think that for some reason the old one is still included somewhere, and because of name collision the new one is renamed to "*.2". So I tried these things to get rid of it:
1) [not working] Delete everything, recompile everything
Just deleting everything, that is:
the .externalNativeBuild folder for my module
the build folder for my module
the build folder for my app
And rebuild everything, that is:
Build > Clean Project
Build > Make Module "my module"
Build > Refresh Linked C++ Projects
Build > Rebuild Project
But this still leads to the same UnsatisfiedLinkError
2) [not working] Changing the name of the .so file
Changing the name of the updated library to "libthird_party_library_NEW.so" and changing the cmake file:
set_target_properties( libthird_party_library PROPERTIES IMPORTED_LOCATION ${pathToProject}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_library_NEW.so)
Same error
3) [working, not a good solution] Rename the old ".so" file and include new one
One "solution" which does work is renaming the old ".so" files using refactor > rename to something like "libthird_party_library_OLD.so" and then copying the new third party libraries using the standard name "libthird_party_library.so". But this is of course not a very nice solution, because the old non needed library will be included in the apk.
It turned out to be a problem with linking a versioned shared library in android studio. Similar as in this question and as described here.
The problem is that the internal version number of "libthird_party_library.so" is actually "libthird_party_library.so.2". This can be found by running objdump under linux on the .so file, that is:
objdump -p libthird_party_library.so | grep so
which outputs:
libthird_party_library.so: file format elf64-little
NEEDED libm.so
NEEDED libc.so
NEEDED libdl.so
SONAME libthird_party_library.so.2
required from libdl.so:
required from libm.so:
required from libc.so:
Since the file name as seen by android is "libthird_party_library.so" and android tries to load "libthird_party_library.so.2" it can obviously not find the required library.
Solution
An obvious solution would be to change the filename to "libthird_party_library.so.2", but this doesn't work because android studio only includes libraries ending on .so in the apk (aaargh).
The solution is to change the internal version number to "libthird_party_library_2.so", renaming the file to "libthird_party_library_2.so" and changing the Cmake file to reflect this change.
1) Changing the internal version number can be done under linux with:
rpl -R -e libthird_party_library.so.2 libthird_party_library_2.so libthird_party_library.so
Where the first argument is the internal version number, the second the one we need to change it to and the third the filename. MAKE SURE THE LENGTH OF THE OLD INTERNAL VERSION NUMBER IS THE SAME AS THE NEW ONE!!
2) Change the filename to "libthird_party_library_2.so" using your favorite tool
3) Change this line in the CMake file to
set_target_properties( libthird_party_library PROPERTIES IMPORTED_LOCATION ${pathToProject}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_library_2.so)
Hope this helps!
I'm struggling to include a prebuilt shared library in my android project
The library in question is libusb, which the NDK part of my android project requires.
Everything is compiling and linking OK, i.e. the project is building successfully, but on installing the apk on my device the app is crashing.
The relevant error msg from monitor is:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libusb1.0.so" not found
what i've tried so far is adding the following to my app/build.gradle:
sourceSets{
main {
// let gradle pack the shared library into apk
jniLibs.srcDirs = '/home/me/third-party/libusb-1.0.21/android/libs/'
}
in CMakeLists.txt i've added:
set(libusb_DIR $ENV{HOME}/third-party/libusb-1.0.21/android/libs)
set(libusb_LIB usb1.0)
link_directories( ${libusb_DIR}/${ANDROID_ABI}/ )
target_link_libraries( ${libusb_LIB} )
I've even tried creating a app/src/main/jniLibs dir and manually copying the armeabi-v7a version of the shared lib, libusb1.0.so, in there.
Still getting same error message in Monitor after the apk has been installed..
Give a try to this one, instead of taking the path from env you should try ${CMAKE_SOURCE_DIR}
set(usb_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)
add_library(libusb SHARED IMPORTED)
set_target_properties(libusb PROPERTIES IMPORTED_LOCATION
${usb_DIR}/libs/${ANDROID_ABI}/libusb1.0.so)
target_link_libraries(${libusb})
I try to add a imported library to my project, and link it to another Library.
Here is some part of my code from CMakeLists.txt:
add_library(native-lib SHARED ${sources})
add_library(imported-lib SHARED IMPORTED)
set_target_properties(imported-lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_LIST_DIR}/PathToLibs/${ANDROID_ABI}/imported-lib.so)
In my native-lib, I create an object of a Class which is placed in imported-lib but the app starts crash. (if I debug or run the app then make project works fine)
In the Gradle Console i get an Info: [org.gradle.api.Task] externalNativeBuildDebug: not building target imported-lib because there was no build command for it
How can I build it?
The shared lib currently need to packed into apk manually, one way is to route jniLibs to your shared lib directory. Hope later version could pack it automatically. One example is here,https://github.com/googlesamples/android-ndk/tree/master/hello-libs, it imports one shared lib, one static lib; shared lib is packed to APK with script in app/build.gradle:jniLibs.srcDirs = ['../distribution/gperf/lib']
As a workaround for me is so in the build.gradle. The 'make' must be in PATH.
externalNativeBuild {
cmake {
...
arguments "-GAndroid Gradle - Unix Makefiles",
"-DCMAKE_MAKE_PROGRAM=make"
}
}
I am working on a project in which it has dependency on another library project. Library project has both java files and native SO files.
Accessing JAVA source files (APIs) from the Android project java source doesn't have any problem. But, my native code is dependent on native SO files present in the included library project of android as well.
Library Project Android Project
--------------- ---------------
src/Java files <-- Java files
libs/.so files <-- libs/.so files
.so files are part of the included library project. How can my current Android project native code try to use .so files of the included library project. Currently I am getting linking error of undefined reference to all the functions which are part of the library/libs/.so files.
Please let me know if any one has faced/resolved similar type of issue.
You probably have both projects imported into your Eclipse. But ndk-build knows nothing about Eclipse. If the library comes with its own .mk file that defines PREBUILT_SHARED_LIBRARY, it would be even better. One such example is OpenCV which includes sdk/native/jni/OpenCV.mk file.
But you can simply add path to the .so files to your Android.mk, e.g. put the following lines in the end of your file:
include $(CLEAR_VARS)
LOCAL_MODULE:=LibraryProjectSO
LOCAL_SRC_FILES:=/LibraryProject/libs/library.so
include $(PREBUILT_SHARED_LIBRARY)
Now you can add LibraryProjectSO to the list of LOCAL_SHARED_LIBRARIES.