In an Android project that loads a C library (mylib.so, which includes a JNI API already), I have a CMakeLists.txt that import the prebuilt library, as per the documentation, like so:
cmake_minimum_required(VERSION 3.10.2)
project(ImportMyLib)
set(MYLIB_PREBUILT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/build/arm64/src")
add_library(mylib SHARED IMPORTED)
set_target_properties(mylib
PROPERTIES IMPORTED_LOCATION
"${MYLIB_PREBUILT_PATH}/libmylib.so")
I did print ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/build/arm64/src and checked that ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/build/arm64/src/libmylib.so does exist.
However, libmylib.so is not included in the resulting .aar, and I don't understand why.
My build.gradle does include the CMakeLists.txt above, like so:
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
This is similar to this question, except that it seems there that there was a need to add an IMPORTED target (because of the ExternalProject_Add), whereas here I'm trying to import an already built library.
What am I missing?
You can explicitly request libmylib.so to be included:
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
targets "mylib" # matches add_library(mylib SHARED IMPORTED)
}
}
I had missed this part of the documentation:
If you want Gradle to package prebuilt native libraries that are not used in any external native build, add them to the src/main/jniLibs/ABI directory of your module.
Versions of the Android Gradle Plugin prior to 4.0 required including CMake IMPORTED targets in your jniLibs directory for them to be included in your app.
[...]
If you are using Android Gradle Plugin 4.0, move any libraries that are used by IMPORTED CMake targets out of your jniLibs directory to avoid this error.
Moving mylib.so to src/main/jniLibs/ABI does work indeed.
Related
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 !
I need to link a, prebuilt ".a" static library to an Android Studio project, using CMakeLists.txt.
The .a library was properly built to armeabi, armeabiv-7a, mips and x86 (it can even be "objdumped" for "content checking") and the ".h" files are just right as well.
The goal isn't to recompile the library sources along with my Android Studio project native sources.
Also, please do not refer to solutions using NDK + Andoid.mk (CMakeLists.txt only).
Since there is no working example on this matter on the web (including the Google NDK documentation and SO), please provide every change needed to the project files and/or project structure.
I keep the ".a" file and its "include" directory on a local folder, so as a meta reference to the this location, please consider /lib.a and /include.
Thank you.
After a long research on this subject, this is a working solution, with a couple of minor issues.
Issue #1:
This should work by placing the libxyz.a lib file and its include directory at {AndroidStudioProjects folder}/{The Project's name}/app/libs but for some (still unknown) reason, on my system it never worked like that.
I managed to make it work by placing both (lib file and include dir) at: {AndroidStudioProjects folder}/{The Project's name}/app/src/main/cpp/libs (which had to be created).
Issue #2:
I have faced some 32bit x 64bit linking issues so, at this point, I have given up on "fat APKs" and kept it 32bit only.
What did I do
On CMakeLists.txt add:
add_library(xyz STATIC IMPORTED)
set_target_properties(xyz PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libxyz.a)
And on target_link_libraries (to your shared native lib), you must add the "xyz" reference:
target_link_libraries(
#the target shared lib:
native-lib
#other libs to link go here
xyz)
Extra:
If you want to be able to include the headers to libxyz.a on your C++ code by using the default include dir, like this:
#inlcude <xyz.h>
You must add it to CMakeLists.txt:
include_directories( ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/include )
Making the output 32bit only
On build.gradle (Module:app) go to the "android defaultConfig" block, right before "externalNativeBuild" and add the ndk abiFilters:
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.your.project"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
abiFilters 'armeabi-v7a', 'x86'
}
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
Please feel free to improve this.
Create a submodule to your project.
put your *.a files in the appropriate libs/armAppropriate/nameOfLib.a
in your cmakelists.txt add the following lines
set(import-lib-location ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs)
make sure this matches the location of your libs folder, do not use absolute path
put your .h files in the include directory of the submodule main.cpp.include
add the following to your CmakeLists.txt file
include_directories(include/)
add_library(nameOfLib STATIC IMPORTED )
set_target_properties(crypto
PROPERTIES IMPORTED_LOCATION ${import-lib-location}/${ANDROID_ABI}/nameOfLib.a)
target_link_libraries( # Specifies the target library.
your_main_cpp_file
nameOfLib
)
Your static lib will be available through api written in your main cpp file and java/kotlin code written in this module
In your build.gradle of your main module write
api project(path: ':project_that_contains_a_libs')
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})
With Android Studio 2.2, and the new C++ support they added; can I now write and compile inside android studio, or do I need to compile and import my libraries separately
Short answer: Yes, you can.
Here is what you can do 1
1) In Android Studio, right click on your module ==> New ==> Package
2) name the package (folder) cpp (or you can name it jni)
3) you will see the cpp directory on the left.
4) You can create .cpp, .h and other files within that folder.
Nowm you have to tell gradle how to build that.
You need install CMake. 2
1) Go to Preferences ==> Android SDK ==> SDK Tools ==> CMake
2) Select that and click Apply and Ok
Now, you need to add a CMakeLists.txt file to your project.
Path: my_project/app/CMakeLists.txt
This is what the file should look like:
# https://developer.android.com/studio/projects/add-native-code.html#create-cmake-script
# Minimum version of CMake
cmake_minimum_required(VERSION 3.4.1)
# adding CEC library
# add_library structure: add_library(lib_name lib_type_STATIC_or_SHARED source_file_path)
add_library(my_lib_name SHARED src/main/jni/my_cpp_file.cpp)
# include_directories is to provide the path to you native lib code
# include_directories structure: include_directories(native_lib_folder_path)
include_directories(src/main/jni/)
# adding Android log library
# find_library is used to find NDK API libraries (built in NDK libs)
# find_library structure: find_library(name_you_want_to_call_the_lib lib_name_in_ndk_api)
find_library(log-lib log)
# linking log lib to our native lib
# once you find the library, you have to link that library with your native library
# target_link_libraries structure: target_link_libraries(you_native_lib lib_found_using_find_library)
target_link_libraries(my_lib_name ${log-lib})
And final step: add the following to your build.gradle:
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
You should be able to build it now.
th3pat3l's answer is works fine, but the official documentation for how to add C++ to a project is a little different. Here it is:
https://developer.android.com/studio/projects/add-native-code.html#create-sources
The main difference is the use of file->new->package. The package concept is for adding a java package and has a side effect of creating a folder.
You can do the same thing more directly by switching to project view and just creating the folder where you want it in the directory.
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"
}
}