On my host system (Ubuntu, 64Bit) I use gcc/g++
compilers to crosscompile my library for my Android app (arm64-v8a). On calling functions from my App I receive messages that libraries like libc.so.6
or libstdc++.so.6
cannot be found.
Within my /usr
directory I have an aarch64-linux-gnu
folder containing bin
, include
and lib
folders.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.6.0)
set(CMAKE_TOOLCHAIN_FILE android.toolchain.cmake)
project(testlibrary)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STYANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# find header & source
file(GLOB_RECURSE SOURCE_CPP "src/*.cpp")
file(GLOB_RECURSE HEADER "src/*.h")
add_library(${PROJECT_NAME} SHARED
${SOURCE_CPP}
${HEADER}
)
source_group("Header include" FILES ${HEADER})
source_group("Source src" FILES ${SOURCE_CPP})
android.toolchain.cmake:
cmake_minimum_required(VERSION 3.6.0)
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc")
set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++")
set(CMAKE_ANDROID_NDK /home/ubuntu/Android/Sdk/ndk/21.4.7075529)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
The error messages are the following:
dlopen failed: library "libc.so.6" not found: needed by /my/lib/path/testlib.so in namespace classloader-namespace
or
dlopen failed: library "libstdc++.so.6" not found: needed by /my/lib/path/testlib.so in namespace classloader-namespace
Do I have to set a Sysroot or other paths so my libraries are found within my toolchain file and which path(s) do I use?
EDIT1: Adding the aarch64-linux-gnu
folder to my build directory and explicitly including
target_link_libraries($PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/aarch64-linux-gnu/lib/libstdc++.so.6)
# also any other lib, e.g. libstdc++.so, libc.so and libc.so.6 don't work
still results in the mentioned error message.
I made a minimal example of the error using the .cpp
and .hpp
files below which results in this case in libc.so.6 not found
. Removing the malloc line also removes the error messages. Calling the testFunc also return the correct value to my App which I can display.
src_file.cpp
#include "header_file.hpp"
#include <stdlib.h> // for malloc
int testFunc_(){
char* buffer;
buffer = (char *) malloc (10);
return 42;
}
header_file.hpp
extern "C" int testFunc_();
I also added the following lines to my android.toolchain.cmake
file (I copied the folder from /usr/aarch64/linux-gnu/ to my build dir)
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
set(CMAKE_INSTALL_RPATH "")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
set(LDFLAGS="-Wl,-rpath,../aarch64-linux-gnu/lib")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LDFLAGS}" CACHE INTERNAL "" FORCE)
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} ${LDFLAGS}" CACHE INTERNAL "" FORCE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LDFLAGS}" CACHE INTERNAL "" FORCE)
set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} ${LDFLAGS}" CACHE INTERNAL "" FORCE)
EDIT2:
On running readelf -d 'path/to/lib'
I get the following (necessary I suppose) entries
Tag Type Name/Value
0x000...1 (NEEDED) Shared library: [libc.so.6]
0x000..1d (RUNPATH) Library runpath: [/home/username/Desktop/projectfolder/aarch64-linux-gnu/lib]
Adding the following line to my CMakeLists.txt
(after removing the RPATH
related stuff from my toolchain file or changing them also to ./
) should allow me to add the libraries right next to my library.so
in the build folder (arm64-v8a).
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath,./")
There is no RPATH
tag. The RUNPATH
entry is the location of my .so.6
and .so
files I copied from the /usr/aarch64-linux-gnu
folder. I think my main problem is bundling the necessary libraries correctly within my application as David Grayson implicated.
EDIT3:
Running file libc.so.6
also shows its an ELF 64-bit LSB shared object with ARM aarch64 architecture dynamically linked for GNU/Linux 3.7.0, interpreter /lib/ld-linux-aarch64.so.1, stripped
EDIT4:
Within my app/build.gradle
I have the following lines
if(isNewArchitectureEnabled()) {
externalNativeBuild {
ndkBuild {
arguments "APP_PLATFORM=android-12",
"APP_STL=c_++shared",
"NDK_TOOLCHAIN_VERSION=gcc", // was clang before
"GENERATED_SRC_DIR=$buildDir/generated/source",
"PROJECT_BUILD_DIR=$buildDir",
"REACT_ANDROID_DIR=${reactNativeRoot}/ReactAndroid",
"REACT_ANDROID_BUILD_DIR=${reactNativeRoot}/ReactAndroid/build",
"NODE_MODULES_DIR=$rootDir/../node_modules"
cflags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
cppFlags "-std=c++17", //maybe 11 here(?) tried out both my App and .so to 11 but also no success
targets "myapp_appmodules"
}
}
}
and also
packagingOptions {
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libm.so'
pickFirst 'lib/arm64-v8a/libm.so.6'
pickFirst 'lib/arm64-v8a/libstdc++.so'
pickFirst 'lib/arm64-v8a/libstdc++.so.6'
pickFirst 'lib/arm64-v8a/libc.so'
pickFirst 'lib/arm64-v8a/libc.so.6'
}
Am I probably using a wrong compiler/give the standalone toolchain within my ndk folder a try!
2
Answers
I solved it changing my compilers (
CMAKE_C_COMPILER
andCMAKE_CXX_COMPILER
) within the toolchain file and leaving my CMakeLists.txt as it was in the first place.using Android API level 21.
You either need to link those libraries statically into your executable (
-static
at link time might work) or you need to ship them with your executable and put them somewhere the executable will find them, like in the same directory.I’m not very familiar with Android but there might also be a way to have the target Android system provide those libraries at run time, since they are very common and used widely.