Include GLES to CMakeLists in Android NDK - android

In Android NDK old version, we include GLES like this:
LOCAL_LDLIBS += -lGLESv1_CM
But in newest version, Android uses CMakeLists instead of Android.mk with the same purpose. So how to add GLES/GLES2/GLES3 dependency to CMakeList file? Thank you!

The difference between the gradle scripting ndk module and cmakelist external tool is the way to define your script. In this case,
you need to create your CMake script (CMakeLists.txt, and change your gradle file to activate the external tool):
CMakelists:
cmake_minimum_required(VERSION 3.4.1)
# now build app's shared lib
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
add_library(gljni SHARED
your_code.cpp)
# add lib dependencies
target_link_libraries(gljni
android
log
EGL
GLESv2) #here you can put your opengl linking library.
The command target_link_libraries specifies the libraries that they are going to be linked.
In the gradle file you need to specify the external native build, adding cmake options such as compiler, android native version etc.
externalNativeBuild {
cmake {
// Available argumetns are inside ${SDK}/cmake/.../android.toolchain.cmake file
arguments '-DANDROID_PLATFORM=android-9',
'-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=gnustl_static'
}
}
Hope this helps.
Cheers
Unai.

Related

Unable to import standard libs to header files in native android project [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm trying to compile a PC C++ project to android.
I compiled the template example and it's working just fine also on my device.
At first, I created just a simple header file, but I cant import simple standard libraries, such as:
#include <string>
The odd thing is that if I change it to a cpp file, everything is imported just fine.
This is what I've done:
CMakeList.txt
# 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.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror")
# 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.
# now build app's shared lib
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).
native-lib.cpp
BoolPair.h
)
# 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.
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)
# 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})
app build.gradle
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared"
cppFlags += "-std=c++11"
}
}
}
You haven't specified which language you want to support in your CMake file. The common CMake idiom is to specify a project() call at the top of your file, which can optionally specify the target language:
cmake_minimum_required(VERSION 3.4.1)
project(MyProjectName CXX)
When a language is not specified, CMake enables both C and C++ languages by default.
It is unclear how you were able to add only a .h file to your target native-lib. This typically results in a CMake error:
CMake can not determine linker language for target
Regardless, in your case, it appears CMake chose a C compiler because the language was not explicitly specified. With a C compiler, #include <string> is not supported.
On the other hand, by including a .cpp file along with the header, CMake now determines this is C++ source code based on the file extension. In this case, a C++ compiler is used and <string> is accepted.

Issue with compiling bundled libs in Android Studio/Gradle

I want to compile libs that are bundled in my project. And I run into 2 issues.
First of one that Cmake does not seems to detect/include that directory.
Second one is after bundled directory is detected/included instead of android toolchain a system's one is used to compile libs.
As workaround to 1st issue I added if(ANDROID) to add that directory so it can be included.
if(EXISTS "${CMAKE_SOURCE_DIR}/libs/CMakeLists.txt")
message(STATUS "Using bundled libraries located at ${CMAKE_SOURCE_DIR}/libs")
if(ANDROID)
add_subdirectory(libs)
else()
include(libs/CMakeLists.txt)
endif()
else()
So for me expected result should follow like this include libs/CMakeLists.txt and build libs using toolchain provided by NDK
If you are trying to use non-ndk prebuilt library for your native component, then add those library details into CMake as mentioned below.
add_library( imported-lib
SHARED
IMPORTED )
set_target_properties( # Specifies the target library.
imported-lib
# Specifies the parameter you want to define.
PROPERTIES IMPORTED_LOCATION
# Provides the path to the library you want to import.
imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
https://developer.android.com/studio/projects/configure-cmake#add-other-library
For building native library using cmake system.
define CMakeLists.txt in your module(local source code to be used for generating lib).
add_library(xyz STATIC
folder-name/xyz.cpp)
target_include_directories(xyz PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/..)
define CMakeLists.txt in your android app module cpp folder.
cmake_minimum_required(VERSION 3.4.1)
/* using existing ndk lib , if you want you can remove this */
build native_app_glue as a static lib.
add_library(native_app_glue STATIC
${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
Import the CMakeLists.txt for the glm library
add_subdirectory(glm)
/* require if u r adding header files location */
target_include_directories(game PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/data
${ANDROID_NDK}/sources/android/native_app_glue)
add lib dependencies
target_link_libraries(
native_app_glue
xyz
)
define app module build.gradle
android {
compileSdkVersion 28
defaultConfig {
applicationId 'com.google.sample.tunnel'
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName '1.0'
}
externalNativeBuild {
cmake {
version '3.10.2'
path 'src/main/cpp/CMakeLists.txt' // location of second(app module) CMakeLists.txt
}
}
}
Also check CMake build commands to verify what all parameters are used during build.
Check this file
app.externalNativeBuild\cmake\debug\x86\cmake_build_command.txt
So this is how it builds libcurl it does configure it 1st then compile using wrong toolchain. I did found something here https://developer.android.com/ndk/guides/other_build_systems but it does export for 1 toolchain per build. Mine is using 2 abi's
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
As you can see it's using ExternalProject_Add instead.
#-----------------------------------------------------------------
# Build bundled cURL library
#-----------------------------------------------------------------
if(BUNDLED_CURL AND (BUILD_CLIENT OR BUILD_SERVER))
ExternalProject_Add(
bundled_curl
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/curl
CONFIGURE_COMMAND ./configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/libs/curl
--enable-shared=no --enable-static=yes
--enable-http --enable-ftp --disable-file
--disable-ldap --disable-ldaps --disable-rtsp
--enable-proxy --disable-dict --disable-telnet
--disable-tftp --disable-pop3 --disable-imap
--disable-smb --disable-smtp --disable-gopher
--without-ssl --without-libssh2 --without-nghttp2
--without-gssapi --with-zlib
--disable-ares --enable-threaded-resolver
--enable-ipv6 --enable-unix-sockets
--without-libidn2 --disable-manual
--disable-sspi --enable-libgcc
--without-libmetalink --without-libpsl
--without-librtmp ${CROSS_COMPILE32_FLAGS}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libs/curl
BUILD_COMMAND make
INSTALL_COMMAND make install
BUILD_IN_SOURCE 1
)
set(CURL_BUNDLED_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/libs/curl/lib/libcurl.a")
set(CURL_BUNDLED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/libs/curl/include")
endif()

How to add prebuilt *.so libraries in android studio?

I am trying to integrate the Hyperledger indy SDK. However, when running my code I get the error
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.UnsatisfiedLinkError: dlopen failed: library "libgnustl_shared.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1657)
I am trying to follow the documentation provided in the project repo. I tried using the sample project on this blog .
I was able to build the *.so libraries under a linux virtual machine, the copied the built files in my android studio project on windows.
I added the files inside my project's jniLibs forlder for each architecture.
Added the code to load the library inside my mainActivity
static{
System.loadLibrary("indy");
}
Tried creating a CMake file
cmake_minimum_required(VERSION 3.4.1)
add_library(indy SHARED IMPORTED)
include_directories(src/main/jniLibs/${ANDROID_ABI}/include)
My gradle file includes:
android{
defaultconfig{
...
ndk{
moduleName "indy"
abiFilters 'armeabi-v7a'
}
}
...
sourceSets {
main {
jniLibs.srcDir 'src/main/jniLibs'
}
}
externalNativeBuild {
cmake {
path file('../CMakeLists.txt')
}
}
}
Still, keep on getting the same error when I launch the app.
I am aware that the bash script that builds the libraries on linux uses the android-ndk-r16b-linux-x86_64 tools so I tried downgrading my ndk in android studio to use the same version but had no luck.
The output of the build script is
include/
indy_anoncreds.h
indy_core.h
...
lib/
libindy.a
libindy.so
libindy_shared.so
How can I use this libraries in my android studio project?
The issue is mainly related to the nature of libraries. Libraries are dynamic in Android and needs to be linked at runtime.
libindy.so depends on stl, openssl, libsodium and libzmq.
You will find libgnustl_shared.so in NDK.
All the other needed prebuilt libraries are also available here.
What you need to do is make sure these libraries are present in the jniLibs folder and load these in order libraries before libindy.
System.loadLibrary("libgnustl_shared");
.
.
System.loadLibrary("indy");
Alternate approach:
There is a subproject in Indy where we are using libindy as dependency and we try to create a one fat dynamic library which has all the dependencies.
Link
If you follow the steps like vcx you dont have to have all the defendant l libraries in jniLibs as they will be already part of final .so file
The command which make one fat dynamic library with all the symbols and dependencies is this (from the link pasted above)
${LIBVCX}/target/${CROSS_COMPILE}/release/libvcx.a \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libz.so \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/libm.a \
${TOOLCHAIN_DIR}/sysroot/usr/${NDK_LIB_DIR}/liblog.so \
${LIBINDY_DIR}/libindy.a \
${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so \
${OPENSSL_DIR}/lib/libssl.a \
${OPENSSL_DIR}/lib/libcrypto.a \
${SODIUM_LIB_DIR}/libsodium.a \
${LIBZMQ_LIB_DIR}/libzmq.a \
${TOOLCHAIN_DIR}/${CROSS_COMPILE_DIR}/${NDK_LIB_DIR}/libgnustl_shared.so -Wl,--no-whole-archive -z muldefs

Android NDK Linker failure for armeabi-v7a: "PLT offset too large, try linking with --long-plt"

When trying to build a signed APK, it fails with ~100 lines repeating:
Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: PLT offset too large, try linking with --long-plt
I've added --long-plt to the arguments:
externalNativeBuild {
cmake {
...
arguments '-DANDROID_STL=c++_static', '-Wl,--long-plt'
cppFlags "-frtti -fexceptions", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_shared"
}
}
But it doesn't seem to change anything.
It works with non-signed (debug) apk generation and works with arm64-v8a.
I'm dealing with >1GB of native code, so I'm guessing that's the main reason.
It seems there is almost no documentation or search result regarding this.
Does --long-plt need to be put somewhere else? If not, is there another setting that can be changed? Or would splitting the code into separate libraries help?
Here's the CMakeLists.txt for reference:
string(REPLACE "." "/" JAVA_GEN_SUBDIR ${JAVA_GEN_PACKAGE})
set(JAVA_GEN_DIR ${Project_SOURCE_DIR}/src/main/java/${JAVA_GEN_SUBDIR}/../../../../../generated)
# configure import libs
set(distribution_DIR ${PROJECT_SOURCE_DIR}/distribution)
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Note: One could use a 'GLOB' here, but newly added source files won't auto-regen build files
# After adding files, you'd need to 'touch' the CMakeLists.txt to re-gen
# SWIG required for build. Easy install is "brew install swig"
#Site: http://swig.org
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
# Remove old java files, in case we don't need to generate some of them anymore
#file(REMOVE_RECURSE ${JAVA_GEN_DIR})
# Ensure file recognized as C++ (otherwise, exported as C file)
set_property(SOURCE src/main/cpp/${LIBRARY_NAME}.i PROPERTY CPLUSPLUS ON)
# Setup SWIG flags and locations
set(CMAKE_SWIG_FLAGS -c++ -package ${JAVA_GEN_PACKAGE})
set(CMAKE_SWIG_OUTDIR ${JAVA_GEN_DIR})
# Export a wrapper file to Java, and link with the created C++ library
swig_add_module(${LIBRARY_NAME}_Wrapper java ${SWIG_I_FILE})
swig_link_libraries(${LIBRARY_NAME}_Wrapper ${LIBRARY_NAME})
# Include a location to the header files
include_directories(
src/main/cpp
${NativeLibPath}
${LUAPATH}
)
set(LUAPATH ${NativeLibPath}/lua)
file(GLOB ALL_SOURCE_FILES
"src/main/cpp/*.cpp"
"${NativeLibPath}/*.cpp"
"${LUAPATH}/*.c"
)
# 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.
${LIBRARY_NAME}
# Sets the library as a shared library.
SHARED
# Provides the list of files to compile.
${ALL_SOURCE_FILES} )
target_include_directories(${LIBRARY_NAME} PRIVATE)
# 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.
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 )
# 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.
${LIBRARY_NAME}
android
# Links the target library to the log library
# included in the NDK.
${log-lib}
)
I agree there is not so much documentation on internet, even if we can find some.
First, try to modify your configuration file:
externalNativeBuild {
cmake {
...
arguments '-DANDROID_STL=c++_static'
cppFlags "-frtti -fexceptions", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_shared", "-Wl,--long-plt"
}
}
Let me know, if it changes anything?

Building c++ projects which have cmake build files for Android using NDK

I have to build 2 separate C++ projects which have Cmake build files setup for different platforms. I want to build them both for Android using NDK so that I can use them as prebuilt libs in Android Studio.
How do I build them for Android using NDK to generate a .a/.so for Arm architectures? Can I do it using cmake itself? Please provide detailed steps
Finally when I have 2 libraries, how do I integrate to Android Studio?
I kind of learnt how to create Android.mks for prebuilt libraries from this link
Using Pre-built Shared Library in Android Studio
But my lib2 depends on lib1 for both compilation and running. Jni code will depend on the combined library of both lib2 and lib1
I am new to NDK. So please provide detailed answers
Most likely, the CMake scripts that work for other platforms will require some changes for Android. Also, we often need special treatment for external dependencies, e.g. if we want CMake to find the correct version of boost.
But the main skeleton of CMakeLists.txt should be a good start. You can run CMake 'manually' for your libraries:
cmake \
-DCMAKE_TOOLCHAIN_FILE=${NDK_ROOT}/build/cmake/android.toolchain.cmake \
-DANDROID_NDK=${NDK_ROOT} \
-DANDROID_ABI=armeabi-v7a \
-DANDROID_PLATFORM=android-19 \
-DANDROID_STL=c++_shared \
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${LIB1_DIRECTORY}/libs/armeabi-v7a \
${LIB1_DIRECTORY}
In the main CMakeLists.txt that builds your JNI wrapper, you can add
add_library(lib1 SHARED IMPORTED)
set_target_properties(lib1 PROPERTIES IMPORTED_LOCATION ${LIB1_DIRECTORY}/libs/armeabi-v7a/lib1.so )
target_link_libraries(jni_wrapper lib1 … log)
Android Studio will not build lib1.so for you, but it will pick it from the correct location and pack it into the APK.
Same trick with IMPORTED will provide lib1 for build of lib2 if the CMake script does not already handle this dependency.

Categories

Resources