Now that Android Studio 2.2 is released officially, I'm migrating from my old ndk-build process to try and use CMake within AS. As I'm incorporating several codebases from within my company (that I can't edit) that make heavy use of C++11 code (including the dreaded std::to_string() method), the only way I can compile is with a select few configuration options - all of which I discovered earlier when beginning work with ndk-build. (see below)
So everything compiles again and builds into the APK - and I 100% verify that my output shared library exists in the APK, but I'm unable to successfully use System.loadLibrary('mylibrary')
- and it turns out this is because the dependency libc++_shared.so is missing.
As in, I get the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
In my old ndk-build process, I always wound up with the 2 libraries (mylibrary.so and libc++_shared.so) in my output folder, which thereby got bundled together into the app. It seems the CMake toolchain isn't bundling libc++_shared.so at all (indeed, it's not found in the APK).
I've been banging my head on this for 6 hours. Can I somehow get the CMake toolchain to bundle this missing library? Any clues?
.
.
My settings:
In gradle.build:
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=c++_shared', '-DANDROID_TOOLCHAIN=gcc', '-DANDROID_PLATFORM=android-16'
}
}
And my CMakeLists.txt (filenames cut out for brevity):
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=gnu++11")
include_directories(.)
include_directories(./other)
set(my_SRCS jniInterface.cpp
etc.cpp)
add_library(mylibrary SHARED ${my_SRCS})
target_link_libraries(mylibrary atomic log)
I wrote a CMake config that should package the STL files:
https://github.com/jomof/ndk-stl/blob/master/ndk-stl-config.cmake
Copy this file next to your CMakeLists.txt
and inside CMakeLists.txt
do
include(ndk-stl-config.cmake)
Let me know if you have problems
I just add this script to moudle's build.gradle:
externalNativeBuild {
cmake {
cppFlags ""
arguments "-DANDROID_STL=c++_shared"
}
}
it will package 'libc++_shared.so' in the apk file
add this in your build.gradle (Module: app)
externalNativeBuild {
cmake {
cppFlags "-std=c++14 -fexceptions -frtti"
arguments "-DANDROID_ARM_NEON=TRUE",'-DANDROID_STL=c++_shared'
}
}
As Gerry pointed out, the latest changes to the audio-echo sample project (https://github.com/googlesamples/android-ndk/pull/298) include changes that worked for me. I added this to the bottom of my CMakeLists.txt file.
# Android Studio CMake does not pack stl shared libraries, so app needs to pack
# the right shared lib into APK. The following code find right stl type and copy
# the needed shared lib into app's app/src/main/jniLibs, android studio assembles
# it into the final APK
# Helper function to retrieve shared stl path and name in NDK
# stl_path: the path to the NDK's shared lib path; empty if not using shared stl
function(get_stl_info stl_path stl_name)
# assume app not uses shared stl lib
set(${stl_path} "" PARENT_SCOPE)
if(NOT ${ANDROID_STL} MATCHES "_shared")
return()
endif()
# using shared lib, config lib name and path
if("${ANDROID_STL}" MATCHES "c\\\+\\\+_")
# app uses c++_shared for stl type
set(stlPath "llvm-libc++/libs/${ANDROID_ABI}")
set(stlName "libc++_shared.so")
elseif(${ANDROID_STL} MATCHES "gnustl_")
set(stlPath "gnu-libstdc++/4.9/libs/${ANDROID_ABI}")
set(stlName "libgnustl_shared.so")
else()
# this sample not supporting other stl types
message(FATAL_ERROR "Not Suppored STL type: ${ANDROID_STL}")
return()
endif()
set(${stl_path} ${ANDROID_NDK}/sources/cxx-stl/${stlPath} PARENT_SCOPE)
set(${stl_name} ${stlName} PARENT_SCOPE)
endfunction()
# force copying needed shared stl lib into ${project}/app/src/main/jniLibs
# so it will be packed into APK
get_stl_info(ndk_stl_path ndk_stl_name)
if(NOT ${ndk_stl_path} STREQUAL "")
set(jniLibs_dir "${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs")
add_custom_command(TARGET mylibrary PRE_BUILD
COMMAND "${CMAKE_COMMAND}" -E
copy ${ndk_stl_path}/${ndk_stl_name}
"${jniLibs_dir}/${ANDROID_ABI}/${ndk_stl_name}"
COMMENT "Copying Shared library to the packing directory")
endif()
I guess it's a workaround that we'll be able to do without some day... Note you have to change the line add_custom_command(TARGET mylibrary PRE_BUILD
and replace mylibrary
with your target name.