I am trying to compile the source code for multiple architectures and multiple API levels of Android NDK based on the compilation flags (by dynamically passing path of Application.mk to the ndk-build command). It was going fine till r12. Now I was trying to update my build system to latest NDK r15c and found that it's taking headers from "android-ndk/sysroot/..." path instead of depending on the APP_PLATFORM flag from Application.mk file
APP_PLATFORM := android-19
Logs for r12b NDK:
-I/data/android/android-ndk-r10d/platforms/android-19/arch-arm/usr/include
Above include path is present when I try verbose logs for ndk-build (V=1) .
Logs for r15c NDK:
--sysroot
/home/airwatch/Android/android-ndk/sysroot
-isystem
/home/airwatch/Android/android-ndk/sysroot/usr/include/arm-linux-androideabi
Above include path is present when I try verbose logs for r15c NDK.
It will not be possible to configure Standalone Toolchain due to my project requirements. Is there anyway to get rid of this sysroot?
As mentioned in comments above here is full explain: https://android.googlesource.com/platform/ndk/+/master/docs/UnifiedHeaders.md
Unified Headers
Before NDK r14, we had a set of libc headers for each API version. In
many cases these headers were incorrect. Many exposed APIs that didn‘t
exist, and others didn’t expose APIs that did.
In NDK r14 (as an opt in feature) we unified these into a single set
of headers, called unified headers. This single header path is used
for every platform level. API level guards are handled with #ifdef.
These headers can be found in prebuilts/ndk/headers.
Unified headers are built directly from the Android platform, so they
are up to date and correct (or at the very least, any bugs in the NDK
headers will also be a bug in the platform headers, which means we're
much more likely to find them).
In r15 unified headers are used by default. In r16, the old headers
have been removed.
Known Issues
Standalone toolchains using GCC are not supported out of the box. To
use GCC, pass -D__ANDROID_API__=$API when compiling. Note: this is not
something we will be fixing.
Supporting Unified Headers in Your Build
System
Unified headers require only a few changes compared to using the
deprecated NDK headers. For reference, this patch added support to
ndk-build: https://android-review.googlesource.com/c/239934/
The compile time sysroot is now $NDK/sysroot. Previously this was
$NDK/platforms/android-$API/arch-$ARCH.
Pass -isystem $NDK/sysroot/usr/include/$TRIPLE when compiling. The
triple has the following mapping:
Arch Triple
ARM arm-linux-androideabi
ARM64 aarch64-linux-android
MIPS mipsel-linux-android
MIPS64 mips64el-linux-android
x86 i686-linux-android
x86_64 x86_64-linux-android
This is needed for
architecture specific headers such as those in asm/ and machine/. We
plan to teach Clang's driver to automatically search the architecture
specific include directory, but that has yet to be done.
Pass -D__ANDROID_API__=$API when compiling. This define used to be
provided by <android/api-level.h>, but with only one set of headers
this is no longer possible. In the future we will look in to adding
-mandroid-version or similar to Clang so this is automatic.
At link time, change nothing. All link time build behavior should
match the deprecated headers behavior. --sysroot should still point to
$NDK/platforms/android-$API/arch-$ARCH/.
Related
Since Crosswalk is over 40mb. I have decide split my apk to reduce apk size...
I have know how to publish differenk apk on Google Play Store...I have readed documantations...
Documentation says:
Supporting multiple CPU architectures When using the Android NDK, you
can create a single APK that supports multiple CPU architectures by
declaring each of the desired architectures with the APP_ABI variable
in the Application.mk file.
For example, here's an Application.mk file that declares support for
three different CPU architectures:
APP_ABI := armeabi armeabi-v7a mips APP_PLATFORM := android-9
NDK Application Documantation says
The Application.mk file is really a tiny GNU Makefile fragment that
defines several variables for compilation. It usually resides under
$PROJECT/jni/, where $PROJECT points to your application's project
directory. Another alternative is to place it under a sub-directory of
the top-level $NDK/apps/ directory. For example:
$NDK/apps//Application.mk Here, is a short name used to
describe your app to the NDK build system. It doesn't actually go into
your generated shared libraries or your final packages
I have no experience for NDK...watched some videos...
In this question latest answer told
For arm you'd put this line in Application.mk :
APP_ABI := armeabi armeabi-v7a
And for intel x86 :
APP_ABI := x86
And you have to change AndroidManifest.xml to have a
different version for each platform (following the instructions in the
link you provided).
Be carefull, if you run cordova build android again, it will probably
replace all the content of platforms/android, and your changes will be
lost.
To build the project use
platforms\android\cordova\build.bat -release
So if I do integrate my app with NDK and puting APP_ABI variable will split apk cpu architecture?
is there a easy way for this? do I have to do additional steps?
Crosswalk library for single architecture will increase the APK size by 20M. If you find it's over 40M, the library maybe for both of x86 and ARM.
If you are using official packaging tools of Crosswalk, you can choose targeting architecture. If you are using Crosswalk as library reference, you can download the library for different architecture separately from official website.
Do not think I did not search, my Android project (on Eclipse) refuses to recognize std::chrono library. The include is OK in my header file :
#include <chrono>
But when I want use it :
using namespace std::chrono;
I have a : Symbol 'chrono' could not be resolved, and all the functions of chrono are unavailables.
So I use NDK r10e, I add some lines in my Application.mk, which now looks like this :
APP_PLATFORM := android-22
APP_STL := gnustl_static
APP_CPPFLAGS := -std=gnu++11
NDK_TOOLCHAIN_VERSION := 4.8
And in my Android.mk, I add :
LOCAL_CFLAGS += -std=gnu++11
It did not solve my problem. Any ideas ? Bad Eclipse configuration ?
After modifications in mk files, I have build and re-build my project.
This is known problem of GNU libstdc++ in Android NDK. It's built on top of very limited libc (Google's Bionic) and thus can't provide full C++ Standard Library functionality. In particular, std::chrono is almost completely disabled at build time, but not only std::chrono. There are many other classes and functions being disabled, so Google's NDK just don't support C++ fully.
You can switch to LLVM libc++ (APP_STL := c++_static), but it has experimental status in Google's Android NDK and is actually unstable (i.e. it cause crashes in the application even for completely standard C++ code). This instability is caused by the same reason as for GNU libstdc++ - i.e. because it's built on top of very limited libc.
I'd recommend switch to CrystaX NDK - alternative fork of Google's Android NDK, which I've started mainly to solve Google's NDK problems such as non-standard implementations of libc, libc++, etc. CrystaX NDK is developed to work as a drop-in replacement for Google's NDK (except for the fact that it provides fully standard-conforming low-level libraries). In CrystaX NDK, both GNU libstdc++ and LLVM libc++ are much more stable and fully conforming to C++ standard, at least at the same level as they conform to it on GNU/Linux. In particular, std::chrono is fully implemented there and works just fine. Also, in CrystaX NDK, you can use more recent compilers such as gcc-5.3 and clang-3.7, with better support of C++11 and C++14. I'd be happy if it helps you.
I'm trying to compile a native Android library using the Intel c++ compiler.
The library compiles without problems using gcc 4.8 (I'm using some c++11 code) but when I set NDK_TOOLCHAIN := x86-icc, it tries to include the stl headers from gcc-4.6
I've read the intel compiler documentation, but I can't find a way to change the include path on the command line. Also setting NDK_TOOLCHAIN_VERSION to 4.8 or specifying a compiler with -gcc-name has no effect.
Is the path hardcoded into the compiler?
Open the file {ndk}/toolchains/x86-icc/setup.mk and change the variable GCC_TOOLCHAIN_VERSION from 4.6 to 4.8.
At least for my small code sample it worked.
I have a really simple helloworld.cpp program
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World!";
return 0;
}
And I'm trying to compile it for android x86 with the cross-compiler from the toolchain:
/Users/me/android-ndk-r8/toolchains/x86-4.4.3/prebuilt/darwin-x86/bin/i686-android-linux-g++ helloworld.cpp -L "/Users/me/android-ndk-r8/sources/cxx-stl/stlport/libs/x86/" -lstlport_static
However, I get errors:
helloworld.cpp:2:20: error: iostream: No such file or directory
Any idea why?
Check the documentation.html file included with the NDK, under "Standalone Toolchain". It says that if you invoke the compiler in this way you won't be able to "use any C++ STL". However it is possible, as the documentation explains, if you first create a "customized" toolchain installation, using something like the following command:
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-8 --install-dir=/tmp/my-android-toolchain --arch=x86
where $NDK is the path to your NDK directory. Note the --arch=x86 which means that the toolchain is prepared specifically for the x86 Android. This prepares what you need in one directory, including the STL headers and folders. You should then be able to use -lstdc++ to link against the STL (static version), i.e. something like:
/tmp/my-android-toolchain/bin/i686-android-linux-g++ helloworld.cpp -lstdc++
For a more complete explanation, please see the NDK documentation.
The NDK documentation is not entirely accurate, at least not currently. In fact, it states when using the prebuilt toolchain "You won't be able to use any C++ STL (either STLport or the GNU libstdc++) with it.", but this is out of date. I created a small hello world program using the include with the same error. It can be solved without creating your own toolchain though, which is nice if you don't want to have to add one more step to your configuration process and allows you to always use the latest SDK platform without creating a new toolchain every time.
The NDK ships with the source code for several versions of standard C++ libraries: GAbi++, STLport, and GNU STL. Each flavor comes with prebuilt shared and static libs as well. My example below will use stlport.
To use the stand-alone toolchain at its installed location, you can do something like this:
export CXX='$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ --sysroot="$NDK_ROOT/platforms/android-19/arch-arm"'
This, for example, would set your CXX compiler to compile ARM on the OS X system using SDK platform level 19. This much you probably already knew. Also, you would want to export your CC, CPP, LD, AR, and RANLIB if you use it. I also personally create an envar for READELF.
To add support for C++ libs, you could do something like follows:
$CXX helloworld.cpp -I$NDK_ROOT/sources/cxx-stl/stlport/stlport -L$NDK_ROOT/sources/cxx-stl/stlport/libs/armeabi -lstlport_shared
Note that this will link the libstlport_shared.so which will now be required at runtime, so you may need to add a relative path to the command above to support that, depending on your APK structure. If you want to just test this simple case, you can just run this on the emulator as follows:
adb push a.out /data
adb push $NDK_ROOT/sources/cxx-stl/stlport/libs/armeabi/libstlport_shared.so /data
adb shell
# su
# cd /data
# chmod 777 a.out
# ./a.out
To get rid of the headache of dealing with shared library paths, you can also statically link the C++ library in by changing "-lstlport_shared" to "-lstlport_static". There are some consequences of doing this, as explained in the NDK Dev Guide. The biggest issue is due to having the static library linked in multiple places, causing:
- memory allocated in one library, and freed in the other would leak or even corrupt the heap.
- exceptions raised in libfoo.so cannot be caught in libbar.so (and may simply crash the program).
- the buffering of std::cout not working properly
A useful tool is also included to see what dependencies your program has, the readelf tool.
To see what other shared libraries your program requires, you can run the following:
$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-readelf -a a.out | grep NEEDED
Other cool standard tools:
addr2line - convert a stack trace address to a line of code
nm - Displays the symbol table
objdump - displays info on an object
i call one of the functions from gnustl after it runs fine from prebuilt aosp arm-linux-androideabi-gcc --std=c++11 and after crashing error i cant get a backtrace from logs or reason, my hope is turning to crossbuilt qemu-linux-user to run host compiled i686 binary on the arm, difficulty is interacting with crosshost libs aapt from adt always crashes on any other than platform specific libs, unless kernel module packaged update is possible...
I've downloaded a custom toolchain (linaro) to build ARM based Android apps. How do I tell the NDK to use it? Can I define or set something in Android.mk and Application.mk that would allow me to do that? Is there another way?
The NDK makefile system is quite extensible and you can indeed define a different toolchain. You'll need some understanding of how Make works.
Toolchains are discovered and initialized in build/core/init.mk line 261 (in NDKr6, the line # may change in future versions). The initialization code looks for files named config.mk under $(NDK_ROOT)/toolchains/*. So you'll need to add your toolchain in a subdirectory under the NDK toolchains directory, and add a config.mk and setup.mk to that subdirectory. Look at toolchains/x86-4.4.3 and toolchains/arm-linux-androideabi-4.4.3 for examples. You should be able to cut and paste the ARM toolchain config.mk and setup.mk if your toolchain has a standard layout.
Once you've defined a toolchain in the toolchain directory, you can switch to it by setting the NDK_TOOLCHAIN variable inside your Application.mk file.
As the other answer mentions, toolchains are discovered by ndk-build makefile system in $(NDK_ROOT)/toolchains/ and you can mirror ideas you see there. But there are a few extra concepts for supporting non-Android target platforms that are interesting although they may be soon outdated as ndk-build starts to explicitly support other platforms, such as mingw targeting win32 (or other gcc compilers targeting plain 'ol linux).
In config.mk:
TOOLCHAIN_ABIS := (list of ABIs that the toolchain supports)
This is an important definition, because you can use this name in your Application.mk to build using the toolchain for a particular ABI. One of the benefits of corrupting the usage of this definition, is that ndk-build can simultaneously build for multiple ABIs. It always assumes that the platform is Android, but if you want to target win32 using a mingw based toolchain, you can define an "ABI" as x86-win32, and then use this ABI in your Application.mk to select it as an additional target via APP_ABI:= x86-win32 Then in your Android.mk files you can use the TARGET_ARCH_ABI definition to select win32 specific sources and include paths, for example:
ifeq ($(TARGET_ARCH_ABI),x86-win32)
LOCAL_SRC_FILES += my_win32_file.c
LOCAL_CFLAGS += -DSOME_WIN32_SPECIFIC
endif
The final piece is that in setup.mk for your toolchain, it may be insufficient to look at other toolchains as examples, because what setup.mk for a particular toolchain really does is override build settings in default-build-commands.mk, so what you want to do is inspect that file, and redefine things in it that you don't like.
Following the previous example, mingw does not support the noexec flag in the binaries, and you can get rid of this feature by adding the following lines in your setup.mk:
# These flags are used to enforce the NX (no execute) security feature in the
# generated machine code. This adds a special section to the generated shared
# libraries that instruct the Linux kernel to disable code execution from
# the stack and the heap.
TARGET_NO_EXECUTE_CFLAGS := # our platform doesn't support this flag!
TARGET_NO_EXECUTE_LDFLAGS := # our platform doesn't support this flag!
# These flags disable the above security feature
TARGET_DISABLE_NO_EXECUTE_CFLAGS := # our platform doesn't support this flag!
TARGET_DISABLE_NO_EXECUTE_LDFLAGS := # our platform doesn't support this flag!
This is just one example of the many features in default-build-commands.mk that may need to be overridden, and of course it's important to provide TOOLCHAIN_NAME so that the toolchain can be selected via NDK_TOOLCHAIN variable inside your Application.mk file in addition to the ABI methodology I mention above.
well,you can simply add "NDK_TOOLCHAIN_VERSION = 4.9" in your Application.mk