As the title suggests I am trying to link a native .so to an android studio project. I have gone through the docs in android developer website and some more articles but unsuccessful in connecting the .so file with the project.
Whenever I try to run the code I get the following error
CMake Error: The following variables are used in this project, but
they are set to NOTFOUND. Please set them or make sure they are set
and tested correctly in the CMake files: testlib
Here is my CMake file
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
add_library(testlib SHARED IMPORTED)
set_property(TARGET testlib PROPERTY IMPORTED_LOCATION "E:/project/Remote_Native/remote_attempt_1/app/libs/armeabi-v7a/libremotedesktop_client.so")
#find_path(testlib E:/project/Remote_Native/remote_attempt_1/app/libs/armeabi-v7a/RemoteDesktop.h)
find_library(testlib E:/project/Remote_Native/remote_attempt_1/app/libs/armeabi-v7a/libremotedesktop_client.so)
#add_library(remote SHARED IMPORTED)
#set_target_properties(remote PROPERTIES IMPORTED_LOCATION libs/${ANDROID_ABI}/libremotedesktop_client.so )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
${testlib})
target_include_directories()
I have four .so files each for arm64, armeabi, armeabi-v7a, x86. I have harcoded the armeabi-v7a lib in the path, android studio is throwing the above mentioned error when I do that. My actual aim is to dynamically load the library based on the chip in the phone. I am pretty sure that my current code is not achieving that.
Here are my queries
How to solve the error that I am getting? I have tried giving both relative and absolute path but to no avail I am getting the same error.
How do I add a .so and a .h file into a native android studio project? That has variations based on the chip on which the code is running?
When I directly add the .h file to the native folder I can reference the classes and functions in that header in my C code but I am unable to run the code. I have a getInstance() method in the .h file. Whenever I call the
getInstance() function it says undefined refernce to getInstance(). What I understand from that is the '.h' file is linked correctly but the definition of the function of the .h files which are actually present in the .so files are not linked. I believe this will be solved if question 1 and 2 are answered.
Is it necessary for all native android projects to have a .mk file? I didn't add one to my project and think it might be one of the cause for the error that I am getting.
You don't need find_library in your case. For log, the library is resolved by NDK for you; for libremotedesktop_client.so, you know the exact path.
Here is the CMakeLists.txt that will work for you:
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
add_library(remote SHARED IMPORTED)
set_property(TARGET remote PROPERTY IMPORTED_LOCATION "E:/project/Remote_Native/remote_attempt_1/app/libs/${ANDROID_ABI}/libremotedesktop_client.so")
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
log
remote)
Note that using full path (E:/project…) in CMake script is not the best practice; you probably can express the path to this library somehow relative to the path of your CMakeLists.txt, which is ${CMAKE_CURRENT_SOURCE_DIR}.
1-2). First of all, add set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) at the start of your CMakeLists.txt (just after cmake_minimum_required(...)) to allow another search paths for libraries. After this you can find lib just using standard find_library:
find_library(FOO_LIBRARY
foo # Lib's full name in this case - libfoo.so
PATHS path/to/lib/)
if (NOT FOO_LIBRARY)
message(FATAL_ERROR "Foo lib not found!")
endif()
You can use variable ANDROID_ABI to get particular library version, if directory with libraries organised in this way:
- path/to/lib
- armeabi-v7a
- libfoo.so
- arm64-v8a
- libfoo.so
- x86
- libfoo.so
- x86_64
- libfoo.so
So, search path in this case:path/to/lib/${ANDROID_ABI}/
To include headers in project just use include_directories:
include_directories(path/to/headers)
4). .mk files only needed if you use ndk-build (so you don't need any)
Related
Hello I am beginner in Android NDK programming and I need some help getting freetype library to work with my project. I've been trying for 3 hours straight to somehow import freetype to my Android Studio project. I searched on the internet and could not find any solution that was working. I downloaded the library and put it in my cpp folder of the project.But I don't know how to include freetype. Any help would be appreaciated!
This is how my CMakeLists.txt look and for the files that I have added it works for them:
cmake_minimum_required(VERSION 3.10.2)
project("firstnative")
include_directories(stb/stb_lib
GoldFlow/Core
GoldFlow/Graphics
GoldFlow/Math
GoldFlow/glm
GoldFlow/glm/gtc
GoldFlow/entt
GoldFlow/physics
GoldFlow/scripts
GoldFlow/freetype/include
GoldFlow/freetype/include/freetype/
GoldFlow/freetype/include/freetype/config
GoldFlow/freetype/include/freetype/internal
GoldFlow/freetype/include/freetype/internal/services
)
add_library(
Native
SHARED
GoldFlow/Math/GoldMath.cpp
GoldFlow/Graphics/Shader.cpp
GoldFlow/Graphics/Renderer2D.cpp
GoldFlow/Graphics/Camera.cpp
GoldFlow/Graphics/Texture.cpp
GoldFlow/Graphics/SpriteSheet.cpp
GoldFlow/Core/Scene.cpp
GoldFlow/Core/GameObject.cpp
GoldFlow/Core/Application.cpp
GoldFlow/Core/Controls.cpp
GoldFlow/Core/Timer.cpp
GoldFlow/physics/AABB.cpp
GoldFlow/physics/Objects.cpp
GoldFlow/scripts/ControllerScript.cpp
GoldFlow/scripts/CharacterMovingScript.cpp
native.cpp)
add_library(
Freetype
SHARED
GoldFlow/freetype/src/autofit/autofit.c
GoldFlow/freetype/src/base/ftbase.c
GoldFlow/freetype/src/base/ftbbox.c
GoldFlow/freetype/src/base/ftbdf.c
GoldFlow/freetype/src/base/ftbitmap.c
GoldFlow/freetype/src/base/ftcid.c
GoldFlow/freetype/src/base/ftfstype.c
GoldFlow/freetype/src/base/ftgasp.c
GoldFlow/freetype/src/base/ftglyph.c
GoldFlow/freetype/src/base/ftgxval.c
GoldFlow/freetype/src/base/ftinit.c
GoldFlow/freetype/src/base/ftmm.c
GoldFlow/freetype/src/base/ftotval.c
GoldFlow/freetype/src/base/ftpatent.c
GoldFlow/freetype/src/base/ftpfr.c
GoldFlow/freetype/src/base/ftstroke.c
GoldFlow/freetype/src/base/ftsynth.c
GoldFlow/freetype/src/base/fttype1.c
GoldFlow/freetype/src/base/ftwinfnt.c
GoldFlow/freetype/src/bdf/bdf.c
GoldFlow/freetype/src/bzip2/ftbzip2.c
GoldFlow/freetype/src/cache/ftcache.c
GoldFlow/freetype/src/cff/cff.c
GoldFlow/freetype/src/cid/type1cid.c
GoldFlow/freetype/src/gzip/ftgzip.c
GoldFlow/freetype/src/lzw/ftlzw.c
GoldFlow/freetype/src/pcf/pcf.c
GoldFlow/freetype/src/pfr/pfr.c
GoldFlow/freetype/src/psaux/psaux.c
GoldFlow/freetype/src/pshinter/pshinter.c
GoldFlow/freetype/src/psnames/psnames.c
GoldFlow/freetype/src/raster/raster.c
GoldFlow/freetype/src/sfnt/sfnt.c
GoldFlow/freetype/src/smooth/smooth.c
GoldFlow/freetype/src/truetype/truetype.c
GoldFlow/freetype/src/type1/type1.c
GoldFlow/freetype/src/type42/type42.c
GoldFlow/freetype/src/winfonts/winfnt.c
)
find_library(
log-lib
log )
find_library(GLES-lib
GLESv3)
target_link_libraries(
Native
${log-lib}
${GLES-lib}
${Freetype}
)
The error I am getting now is this: C:\Users\infer\AndroidStudioProjects\FirstNative\app\src\main\cpp\GoldFlow\freetype\src\base\ftbdf.c:40:14: error: use of undeclared identifier 'FT_ERR_PREFIXInvalid_Face_Handle'; did you mean 'FT_Err_Invalid_Face_Handle'?
Ok the solution was very simple. All I did actually was I created directory in cpp folder named freetype and in that dir I've put every freetype file and just added that folder as sub directory in CMake and linked at the end and now eveyrthing works. Here is my CMake:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.10.2)
# Declares and names the project.
project("firstnative")
include_directories(stb/stb_lib
GoldFlow/Core
GoldFlow/Graphics
GoldFlow/Math
GoldFlow/glm
GoldFlow/glm/gtc
GoldFlow/entt
GoldFlow/physics
GoldFlow/scripts
GoldFlow/text
)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
Native
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
GoldFlow/Math/GoldMath.cpp
GoldFlow/Graphics/Shader.cpp
GoldFlow/Graphics/Renderer2D.cpp
GoldFlow/Graphics/Camera.cpp
GoldFlow/Graphics/Texture.cpp
GoldFlow/Graphics/SpriteSheet.cpp
GoldFlow/Core/Scene.cpp
GoldFlow/Core/GameObject.cpp
GoldFlow/Core/Application.cpp
GoldFlow/Core/Controls.cpp
GoldFlow/Core/Timer.cpp
GoldFlow/physics/AABB.cpp
GoldFlow/physics/Objects.cpp
GoldFlow/scripts/ControllerScript.cpp
GoldFlow/scripts/CharacterMovingScript.cpp
GoldFlow/text/TextRenderer.cpp
native.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
#sd
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
find_library(GLES-lib
GLESv3)
add_subdirectory(freetype)
target_link_libraries( # Specifies the target library.
Native
# Links the target library to the log and gl es library
# included in the NDK.
${log-lib}
${GLES-lib}
freetype
)
Im using prebuilt android native library: libcrypto.a.
Library is compiled for armeabi, armeabi-v7a and x86.
Structure:
-app
- CMakeLists.txt
- libs
- armeabi
- armeabi-v7a
- x86
Each folder (armeabi, armeabi-v7a and x86) contains folders lib(contains libcrypto.a) and include (contains header files).
CMake code:
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
add_library(crypto STATIC IMPORTED)
set_target_properties(crypto
PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/lib/libcrypto.a)
target_link_libraries( # Specifies the target library.
native-lib
crypto
# Links the target library to the log library
# included in the NDK.
${log-lib})
In my own native-lib i wanna use libcrypto.a. But when i wanna import header file f.e. #include "openssl/md5.h" android studio does not see that file.
And offer me to include one of THREE files from different abis:
"../../../libs/x86/include/openssl/md5.h"
"../../../libs/armeabi/include/openssl/md5.h"
"../../../libs/armeabi-v7a/include/openssl/md5.h"
Is there any way to create one version of my library (native-lib), include only 1 header and let android studio to choose abi automatically?
Smth like:
#include "openssl/md5.h"
but in the same time use 3 abi version.
Or i should use prebuilt included libraries not like that?
#EDIT1
target_include_directories(crypto INTERFACE ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/include)
Not working, getting CMake error.
Before that i have used
target_include_directories(${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/include/)
You need to add an include directory so that the compiler can find openssl/md5.h.
The most idiomatic way to do this would be:
target_include_directories(crypto INTERFACE
${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/include)
Unfortunately, CMake is silly, and doesn't actually let you do this yet on imported library targets, so you have to set the property manually, like so:
set_target_properties(crypto
PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/lib/libcrypto.a
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/include
)
That adds that include directory to the interface of crypto, which means it also gets used when building native-lib, as properties which are preceded with INTERFACE are propagated to the users of that target. Using INTERFACE properties is the natural way in CMake to propagate usage requirements to consumers of a library.
Could you please try to one of the codes below:
include_directories("${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/include")
Or
target_include_directories(native-lib "${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/include")
If I'm not wrong, target_include_directories include files to a specific target. Since you are importing the header file in your native-lib files, target_include_directories must aim the native-lib.. and not crypto.. Those header files are not necessary to crypto... but to native-lib.
For any case, you can set include_directories which will add those header files to all targets (native-lib and crypto).
Also, remember:
1 - Edit your CMakeLists.txt
2 - Perform a project sync
3 - Only after that, open your native-lib.cpp file and try to import the file header file again.
Maybe there is already some answers on this forum about this problem, but i tried a lot of solutions already, and i still didnt solve this problem.
I have to make an android application using C++, wich uses libcurl.
And whatever i do, i can't run my program because it doenst find the library.
In my .cpp, i use this line :
#include <curl/curl.h>
And this is my CMakeLists.txt
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
-lcurl
# Specifies the name of the NDK library that
# you want CMake to locate.
log
-lcurl )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
INCLUDE_DIRECTORIES($/usr/include/)
target_link_libraries( # Specifies the target library.
native-lib
-lcurl
# Links the target library to the log library
# included in the NDK.
${log-lib} )
I used the commands :
sudo aptitude install libcurl4-gnutls-dev
and
sudo aptitude install libcurl-dev
You should rather use the built-in functionality to integrate libcurl:
[...]
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIRS})
add_library(native-lib SHARED src/main/cpp/native-lib.cpp)
target_link_libraries(native-lib ${CURL_LIBRARIES})
As it seems you are cross-compiling for Android, the following will make the curl library that you installed for your Ubuntu available for the compilation (add it before what is above).
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
But it might then be problematic in the linking step, since you installed the library for your Ubuntu and the program you want to compile it with is for Android.
If this does not work, try to have the curl library in your cross-compiling toolset (but I don't know enough about it to tell you how to do it).
I think you need to instruct cmake to find the libcurl dependency.
Please read How_To_Find_Libraries.
And look at find_package and FindCURL module
As a quick-start, add the following to your CMakeLists.txt:
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIRS})
add_library(native-lib SHARED ... )
target_link_libraries(native-lib ${CURL_LIBRARIES})
(even better: use target_include_directories() instead of include_directories()).
I am using Android Studio 2.2.2 with cmake and Android NDK. I have a problem linking .a library (Static lib).
Here is my cmake:
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_VERBOSE_MAKEFILE on)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library(lib_webp SHARED IMPORTED )
set_target_properties(lib_webp PROPERTIES IMPORTED_LOCATION
src/main/jni/${ANDROID_ABI}/libwebp.so)
add_library( # Sets the name of the library.
game-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/main.cpp
src/main/cpp/android_native_app_glue.c
)
target_include_directories(game-lib PRIVATE
../../../../libs/headers/android
)
include_directories($ENV{NDK_MODULE_PATH}/sources/android/native_app_glue/)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
game-lib
# Links the target library to the log library
# included in the NDK.
# ${log-lib}
# Specifies the name of the NDK library that
# you want CMake to locate.
log
android
OpenSLES
z
GLESv2
EGL
dl
)
add_definitions(-g -DANDROID -Wno-write-strings -fsigned-char -Wno-conversion-null)
TARGET_LINK_LIBRARIES(game-lib libtheoraplayer.a)
My linker reports an error
arm-linux-androideabi/bin\ld: error: cannot find -ltheoraplayer
error: undefined reference to 'TheoraVideoManager::TheoraVideoManager(int)'
which is a part of libtheoraplayer.a. Did anyone had similar problem? Any idea how to solve this?
I have the Static lib libtheoraplayer.a present at that location. I even have the Shared lib also, libtheoraplayer.so but I can`t link it either.
Any advice would be appreciated.
Cheers.
To post the answer. As Tsyvarev said, the problem with non-absolute file name for library. When I used absoulte path it worked like a charm.
Thank you.
Cheers.
I am currently writing JNI code for an Android application to use some legacy native code. I chose to use CMake to give it a try (this is my first time using it).
I would like to serialize a quite complex C structure to JSON format using Jansson library. This would to make it more simple to expose it to Java.
Here is my question: How is it possible to import Jansson in my project as a dependency for my own code ?
I tried to import Jansson in my own sources and use a add_subdirectory clause to make it build. As a result, I can see some intermediates CMake files in the output but no actual compiled file.
Here is what my CMake file looks like :
cmake_minimum_required(VERSION 3.4.1)
include_directories(
src/main/cpp/xxx/Include
)
add_subdirectory("src/main/cpp/jansson")
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/xxx/file1.c
src/main/cpp/xxx/file2.c
src/main/cpp/xxx/file3.c
src/main/cpp/xxx/file4.c
src/main/cpp/native-lib.cpp )
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
Any help will be welcomed !!
Okay, so I was just missing to declare the dependency of my library on Jansson. This is made by adding its project name to the existing target_link_library clause.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
jansson
${log-lib} )
In case someone else (well maybe my future self) stumbles on the same problem, here are all the necessary steps to add a native dependency in an Android CMake file:
Find a library already supporting CMake
Import library code in your project (I used git submodule)
Add add_subdirectory clause that points to the folder containing the library CMake file
Add include files to include_directories (hopefully, the imported library set a variable for that, such as JANSSON_INCLUDE_DIRS in my case
Add dependency by adding the library project name to the target_link_libraries clause
Once this is done: poof ! magic ! everything works fine !