I am getting very confused trying to build a simple C library using Android NDK 23 (23.1.7779620). I am using CMake and this is a very simple program:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(mf)
add_library(mf lib.cpp)
lib.hpp:
#pragma once
#include <string>
std::string foo(std::string);
lib.cpp:
#include "lib.hpp"
std::string foo(std::string str) {
return std::string{"test"} str;
}
This is the command line to build:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DANDROID_STL=c _shared -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-29 -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake ..
cmake --build . -v
- The first problem is that I was expecting to link against
libc .so
and notlibc _shared.so
. What is the difference between them? I read this article. But still is not explained the difference betweendlibc
andlibc _shared
- The second problem is even worst, it seems I am using libstdc !
- The 3rd point, I was thinking that the c implementation of clang was under the namespace
std::__1
but I cannot find anything like that.
I know libc _shared is used because of this command:
$ readelf -d libmf.so
Dynamic section at offset 0x76e0 contains 26 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libm.so]
0x0000000000000001 (NEEDED) Shared library: [libc _shared.so]
0x0000000000000001 (NEEDED) Shared library: [libdl.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so]
0x000000000000000e (SONAME) Library soname: [libmf.so]
Running nm it seem I am using symbols from libstdc
:
$ nm -gDC libmf.so | grep '__ndk1'
0000000000003af0 T foo(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >)
U std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::append(char const*, unsigned long)
$ nm -gDC libmf.so | grep '__1'
$
CodePudding user response:
By passing -DANDROID_STL=c _shared
to the CMake invocation you explicitly asked for the shared runtime as opposed to the default runtime.
As explained in the documentation, the rules are simple:
- if all your native code is in a single library, use the static libc (the default) such that unused code can be removed and you have the smallest possible application package.
- As soon as you include an extra library – either because you include a precompiled library from somewhere else or you include an Android AAR file that happens to include native code – you must switch to the shared runtime.
The rationale for the rules is simple: the C runtime has certain global data structures that must be initialized once and must only exist once in memory. If you were accidentally to load two libraries that both link the C runtime statically, you have (for instance) two conflicting memory allocators.
This will result in crashes when you free
or delete
memory allocated by the other library, or if you pass a C STL object like std::string
across library boundaries.
For completeness, in older NDKs libstdc (the GNU C runtime) was also included in the NDK, but as of NDK r18 that is no longer the case.