19

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)
Mete
  • 5,495
  • 4
  • 32
  • 40
  • 2
    This is a known issue in the Android Studio CMake integration: https://code.google.com/p/android/issues/detail?id=214664 – Dan Albert Sep 21 '16 at 20:24
  • 1
    you might try to see if this one: https://github.com/googlesamples/android-ndk/pull/298 could work for you. there might be more than this to be done, give it a try to see if it could help you for the moment – Gerry Sep 21 '16 at 22:11
  • Thanks @Gerry that does indeed work. I might formulate the changes I made into an alternative answer to this thread.. :-) – Mete Sep 22 '16 at 09:16

5 Answers5

19

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

Bub
  • 304
  • 2
  • 6
11

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

Ace Falobi
  • 741
  • 1
  • 8
  • 25
Jomo Fisher
  • 621
  • 5
  • 7
  • 1
    Thanks man, I like the look of this but keep running into the error 'Could not find a package configuration file provided by "ndk-stl"' - I tried changing PATHS "." to PATHS ${CMAKE_CURRENT_LIST_DIR} but still no luck. Will keep trying in the meantime... – Mete Sep 22 '16 at 08:52
  • 1
    Note, although I found another workaround to the problem, I think yours looks easier and more portable if it works, so I would give you the answer if we can figure out that paths issue – Mete Sep 22 '16 at 09:34
  • That message means CMake couldn't locate the package file ndk-stl-config.cmake. Did you name the file ndk-stl-config.cmake and place it next to your CMakeLists.txt? If so, hmmm, two ideas: (1) share a repro project with me on github, (2) paste the full message that you got (build with ./gradlew assemble on command-line) – Jomo Fisher Sep 22 '16 at 14:39
  • EDIT: I accepted Gerry's suggestion to use include(...) instead of find_package(...). He confirmed this worked from his side. – Jomo Fisher Sep 22 '16 at 19:41
  • this works great, changed sample to use this one: it is much cleaner implementation! thanks – Gerry Sep 22 '16 at 20:29
  • We're going to fix this issue in Android Studio for a point release after 2.2. So hopefully you'll only have to work around this way for a little while – Jomo Fisher Sep 24 '16 at 01:07
7

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'
            }
        }
kakyo
  • 10,460
  • 14
  • 76
  • 140
StarXin
  • 71
  • 1
  • 1
  • This should be the accepted answer for Android Studio 3.5.x. – kakyo Dec 25 '19 at 02:47
  • @kakyo There is no flag named 'cppFlags' or 'arguments' : http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.CmakeOptions.html How did you get this to work? – Alan Feb 10 '20 at 22:11
  • 2
    this is under the defaultConfig { .... block – hyena May 19 '21 at 04:28
2

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.

Mete
  • 5,495
  • 4
  • 32
  • 40
0

Add the following line in Application.mk

APP_STL := c++_shared
hosseinkhosravi
  • 406
  • 6
  • 5