I'm using OpenGL ES2 inside an android app inside C++ code.
Compiling and executing the program works as planned, however the IDE itself cannot find the NDK header files leaving my code files ugly:
My cmake file:
cmake_minimum_required(VERSION 3.4.1)
add_library(native-lib
SHARED
openGLRenderer.cpp
androidInterface.cpp
)
target_link_libraries(native-lib
android
log
EGL
GLESv2
)
build.gradle:
...
externalNativeBuild {
cmake {
cppFlags "-frtti"
arguments '-DANDROID_PLATFORM=android-21',
'-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=gnustl_static'
}
...
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
What do I have to do to fix this? Thank you!
I can't believe this.
The fix is to use the other slashes.
So instead of:
#include <GLES2\gl2.h>
do
#include <GLES2/gl2.h>
It still compiled fine and both preview and compile worked in Visual Studio where I had it before.
Have you added the header files to your cmake file with "include_directories"?
cmake_minimum_required(VERSION 3.4.1)
project(GL3Lib)
# now build app's shared lib
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wc++11-extensions -Werror -Wno-deprecated -std=c++11")
add_subdirectory(freetype)
include_directories(freetype/include)
include_directories(common)
include_directories(utils)
include_directories(rendering/text)
file(GLOB UTILS_HEADERS "utils/*.h")
file(GLOB COMMON_HEADERS "common/*.h")
file(GLOB TEXT_HEADERS "rendering/text/*.h")
file(GLOB UTILS_HEADERS "utils/*.h")
set(JNI_SRCS
JNI_Api.cpp)
set(TEXT_SRCS
rendering/text/Font.cpp
)
set(UTIL_SRCS
common/Utils.cpp
)
add_library(gl3 SHARED
${JNI_SRCS}
${TEXT_SRCS}
${UTIL_SRCS}
${UTILS_HEADERS}
)
# MESSAGE( STATUS "CMAKE_SOURCE_DIR: " ${CMAKE_SOURCE_DIR} )
# add lib dependencies
target_link_libraries(gl3
android
freetype
log
EGL
GLESv3
)
Related
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()
I'm trying to implement code from
here
When trying to compile it, I get these errors:
Error:(339) undefined reference to `ANativeWindow_fromSurface'
Error:(340) und
Error:(349) undefined reference to `ANativeWindow_setBuffersGeometry'
Error:(351) undefined reference to `ANativeWindow_lock'
Error:(353) undefined reference to `ANativeWindow_release'
Error:(406) undefined reference to `ANativeWindow_unlockAndPost'
Error:(407) undefined reference to `ANativeWindow_release'
Error:error: linker command failed with exit code 1 (use -v to see invocation)
Information:BUILD FAILED
Information:Total time: 2.012 secs
Information:8 errors
Information:0 warnings
Information:See complete output in console
ANativeWindow gets from 2 c++ .h files, one is
#include <android/native_window.h>
and other
#include <android/native_window_jni.h>
Now, my CMake file looks like this:
cmake_minimum_required(VERSION 3.4.1)
# OpenCV stuff
include_directories(D:\\opencv-3.2.0-android-sdk\\OpenCV-android-sdk\\sdk\\native\\jni\\include)
add_library( lib_opencv SHARED IMPORTED )
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so)
add_compile_options(-std=c++11)
# 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-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.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.
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 the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
-ljnigraphics
lib_opencv
# Links the target library to the log library
# included in the NDK.
${log-lib} )
And my gradle file regarding c++ code:
defaultConfig {
minSdkVersion globalConfiguration.getAt("androidMinSdkVersion")
targetSdkVersion globalConfiguration.getAt("androidTargetSdkVersion")
applicationId globalConfiguration.getAt("androidApplicationId")
versionCode globalConfiguration.getAt("androidVersionCode")
versionName globalConfiguration.getAt("androidVersionName")
testInstrumentationRunner globalConfiguration.getAt("testInstrumentationRunner")
testApplicationId globalConfiguration.getAt("testApplicationId")
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions -Werror -fexceptions -std=c++11"
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips', 'mips64'
}
}
multiDexEnabled = true
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
I would appreciate if someone would help me with this
You need to link against libandroid.
target_link_libraries( # Specifies the target library.
native-lib
-ljnigraphics
-landroid # Add this.
lib_opencv
# Links the target library to the log library
# included in the NDK.
${log-lib} )
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.
I use Android Studio 2.2's cmake to build native code, in the native code I invoked the ffmpeg api, so the ffmpeg library should be packaged. My CMakelists.txt is as below:
cmake_minimum_required(VERSION 3.4.1)
include_directories(libs/arm/include)
link_directories(libs/arm/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).
# Associated headers in the same location as their source
# file are automatically included.
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} )
add_library(avcodec-57 SHARED IMPORTED)
set_target_properties(avcodec-57 PROPERTIES IMPORTED_LOCATION C:/Users/tony/Desktop/MyApplication/app/libs/arm/lib/libavcodec-57.so)
target_link_libraries(native-lib avcodec-57)
target_link_libraries(native-lib avformat-57)
target_link_libraries(native-lib avutil-55)
target_link_libraries(native-lib avfilter-6)
In such case, I can make project successfully, but when I install the apk to emulator and run, it failed and show that "libavcodec-57.so" isn't found.
Then I use tool (analyze apk) to check the apk, found that the ffmpeg library isn't packaged.
I found a way that works for me, not sure it helps you but it might. I'm using Android Studio 2.2, and ran into your problem too.
I created a jar-file, with the prebuilt libraries in it:
lib
--|armeabi
--|--|libMyLIb.so
etc.
by simply creating a folder lib with that contents somewhere, and the executing the command
zip -r myjar.zip lib && mv myjar.zip myjar.jar
Next, I put the jar file in here:
app/libs/myjar.jar
And added these lines to the CMakeLists.txt that builds a native .so-library inside Android Studio. That is, I started with an empty project off the template for calls to native code (the default libnative-lib.so):
# already there:
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
# my addition:
add_custom_command(TARGET native-lib POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs"
$<TARGET_FILE_DIR:native-lib>)
And magically, now if I build the apk, the contents of my jar end up in the final apk. Don't ask me why this works, really, I have no clue, it was accidental.
What this means for me, is that I compile the empty libnative-lib.so, for the only purpose of tricking Android Studio into including my jar.
Perhaps someone finds a cleaner solution, and can point out where my solution is a ridiculous loop that resulted out of misunderstanding gradle and cmake...
I had the exact same problem.
Cmake does not automatically pack third library into the apk , you have to do it yourself.
Here is an exemple with libavcodec and libavutil from ffmpeg.
1- Copy your pre-built lib into app/libs/[abi]/
Exemple : app/libs/armeabi-v7a/libavcodec.so
2- Copy include into app/libs/include
Then in your cmakelist.txt add the libraries you need
find_library( log-lib log )
set(ffmpeg_DIR ../../../../libs) #set path to libs folder
add_library( libavutil SHARED IMPORTED )
set_target_properties( libavutil PROPERTIES IMPORTED_LOCATION ${ffmpeg_DIR}/${ANDROID_ABI}/libavutil.so )
add_library( libavcodec SHARED IMPORTED )
set_target_properties( libavcodec PROPERTIES IMPORTED_LOCATION ${ffmpeg_DIR}/${ANDROID_ABI}/libavcodec.so )
include_directories(libs/include) #add include dir. don't know why ../ not needed
add_library( native-lib SHARED src/main/cpp/native-lib.cpp )
target_link_libraries( native-lib libavcodec libavutil ${log-lib} )
Finally in your build.gradle set jniLibsfolder :
sourceSets.main {
jniLibs.srcDirs = ['libs']
}
Setting jniLibs.srcDir was the key for me to be able to bundle the libs into the apk.
Note that i used libs folder but you can probably use any folder you want to store your pre-built libs.
Found a working sample on github (not mine) : https://github.com/imchenjianneng/StudyTestCase
I suffered the same problem.
Gradle doesn't packaging .so files into apk while I filled CMakeLists.txt correctly, but finally I resolved it.
Add the JniLibs path into sourceSets in local build.gradle as this sample code:
https://github.com/googlesamples/android-ndk/blob/master/hello-libs/app/build.gradle
which is #Gerry mentioned in the comment.
I did:
copy .so libraries into src/main/JniLibs/${ANDROID_ABI}.
ex) mobile/src/main/JniLibs/armeabi-v7a/libavcodec.so
edit CMakeLists.txt
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
# project path (absolute), change it to yours.
set(projectDir C:/Users/Administrator/AndroidStudioProjects/TestApp1)
# headers
include_directories(${projectDir}/mobile/src/main/JniLibs/${ANDROID_ABI}/include)
# sample ndk lib
add_library( native-lib SHARED src/main/cpp/native-lib.cpp )
# FFMPEG libraries
add_library( lib_avcodec SHARED IMPORTED )
set_target_properties( lib_avcodec PROPERTIES IMPORTED_LOCATION ${projectDir}/mobile/src/main/JniLibs/${ANDROID_ABI}/libavcodec.so)
# ...
# (omitted) same codes with lib_avdevice, lib_avfilter, lib_avformat, lib_avutil, lib_swresample, and lib_swscale each.
# ...
target_link_libraries( # Specifies the target library.
native-lib
lib_avcodec
lib_avdevice
lib_avfilter
lib_avformat
lib_avutil
lib_swresample
lib_swscale
)
in build.gradle (app)
build.gradle
android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "your-application-Id"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions"
}
}
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'armeabi', 'armeabi-v7a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
# ADD THIS BLOCK.
sourceSets {
main {
// let gradle pack the shared library into apk
jniLibs.srcDirs = ['src/main/JniLibs']
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
productFlavors {
}
}
hope it helps you.
p.s. I used FFMPEG libraries that built myself.
I am trying to compile my OpenGL application in Android. I'm using [GLM library] (0.9.4)1
The compilation works until I include:
#include <glm/glm.hpp>
This header add cmath and linker complain about:
cmath:102:11: error: '::acos' has not been declared
...
cstdio:107:11: error: '::fprintf' has not been declared
It seems like std have some problem with using std, or libc++ of flags configuration on CMakeLists.txt
My CMakeLists.txt is:
status("")
status("* Adding module Core C++ ")
SET(PROJ_NAME CORE_CPP)
PROJECT(${PROJ_NAME})
# Helper to set libs & bin paths
INCLUDE(${PATH_MAIN}/cmake_tools/scripts/helperPaths.cmake)
# Include header from Module Core
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include )
IF(DEP_GLM)
INCLUDE_DIRECTORIES( ${PATH_GLM} )
ENDIF(DEP_GLM)
# Source
#---------------------------------------------------#
file(GLOB CORE_CPP_SRC
"src/*.cpp"
)
file(GLOB CORE_CPP_HEADERS
"include/*.h"
)
# Create Library
ADD_LIBRARY(${PROJ_NAME} STATIC ${CORE_CPP_SRC} ${CORE_CPP_HEADERS})
#message("Link: ${LIBRARY_DEPS}")
SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" )
SET( LIBRARY_DEPS GLESv2 log android)
TARGET_LINK_LIBRARIES(${PROJ_NAME} ${LIBRARY_DEPS})
status("- module ${PROJ_NAME} added! ")
In previous versions of gcc, It was needed to add #define _GLIBCXX_USE_C99_MATH 1 inside its includes, but it is already added in my version (4.8)
Any idea what is the problem?
I have found the problem, I was including the header INSIDE my namespace, so linker was looking for another namespace into std.
#ifndef MYNAME_MATH_H
#define MYNAME_MATH_H
#include <glm/glm.hpp> // Linker Work
namespace myname
{
//#define _GLIBCXX_USE_C99_MATH 1
//#include <glm/glm.hpp> // Make linker FAIL!
//typedef glm::vec2 Vector2;
//typedef glm::vec3 Vector3;
//typedef glm::vec4 Vector4;
}
#endif // MYNAME_MATH_H