This is the part 2 of “Mastering NDK” article. In the previous part (part 1), we have introduced how to use ndk-build to build Android native projects, and we also covered several advanced techniques to manage and customize the build script for bigger projects.

Although ndk-build is probably more than enough for most of the Android native projects, there might still be demand for the standalone toolchain in some cases. For example, if you already have a C/C++ project which might be quite complex and has a complicated makefile. In that case, you may not want to convert everything to Android.mk and Application.mk. Using standalone toolchain makes more sense in this case, and it allows you to keep your original makefile or reuse most of the original makefile. Therefore, in this part, I will briefly cover the usage of the standalone toolchain, and give a few code examples.

The source code of all examples can be found here: https://github.com/robertwgh/mastering-ndk.

Table of Contents

  1. Before we start
  2. The ndk-build Workflow
  3. Use customized toolchain for your projects
  4. Summary
    Comments

1. Before we start

The Android NDK official document contain a chapter “STANDALONE-TOOLCHAIN”, which gives useful information about the standalone toolchain. However, that document is short of details, and there is no example to demonstrate the usage. Therefore, it might be hard to follow the official document. But it is still a good reference to have anyways.

2. The ndk-build Workflow

Actually, when we use ndk-build, if we enable the debug option V=1 as follows:

ndk-build V=1

We will see what is actually done by ndk-build. The following console print comes from the compilation of example 1.

$ ndk-build V=1
rm -f ./libs/arm64-v8a/lib*.so ./libs/armeabi/lib*.so ./libs/armeabi-v7a/lib*.so ./libs/armeabi-v7a-hard/lib*.so ./libs/mips/lib*.so ./libs/mips64/lib*.so ./libs/x86/lib*.so ./libs/x86_64/lib*.sorm -f ./libs/arm64-v8a/gdbserver ./libs/armeabi/gdbserver ./libs/armeabi-v7a/gdbserver ./libs/armeabi-v7a-hard/gdbserver ./libs/mips/gdbserver ./libs/mips64/gdbserver ./libs/x86/gdbserver ./libs/x86_64/gdbserverrm -f ./libs/arm64-v8a/gdb.setup ./libs/armeabi/gdb.setup ./libs/armeabi-v7a/gdb.setup ./libs/armeabi-v7a-hard/gdb.setup ./libs/mips/gdb.setup ./libs/mips64/gdb.setup ./libs/x86/gdb.setup ./libs/x86_64/gdb.setup[armeabi-v7a] Compile++ thumb: hello <= hello.cpp
/cygdrive/d/development/android-ndk-r10d/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ -MMD -MP -MF ./obj/local/armeabi-v7a/objs-debug/hello/hello.o.d.org -fpic -ffunction-sections -funwind-tables -fstack-protector -no-canonical-prefixes -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp -fno-exceptions -fno-rtti -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -O0 -UNDEBUG -marm -fno-omit-frame-pointer -ID:/development/android-ndk-r10d/sources/cxx-stl/stlport/stlport -ID:/development/android-ndk-r10d/sources/cxx-stl//gabi++/include -Ijni -DANDROID  -Wa,--noexecstack -Wformat -Werror=format-security -fPIE  -frtti   -frtti -fexceptions  -ID:/development/android-ndk-r10d/platforms/android-19/arch-arm/usr/include -c  jni/hello.cpp -o ./obj/local/armeabi-v7a/objs-debug/hello/hello.o && ./obj/convert-dependencies.sh ./obj/local/armeabi-v7a/objs-debug/hello/hello.o.d[armeabi-v7a] Executable     : hello
/cygdrive/d/development/android-ndk-r10d/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ -Wl,--gc-sections -Wl,-z,nocopyreloc --sysroot=D:/development/android-ndk-r10d/platforms/android-19/arch-arm -Wl,-rpath-link=D:/development/android-ndk-r10d/platforms/android-19/arch-arm/usr/lib -Wl,-rpath-link=./obj/local/armeabi-v7a ./obj/local/armeabi-v7a/objs-debug/hello/hello.o D:/development/android-ndk-r10d/sources/cxx-stl/stlport/libs/armeabi-v7a/thumb/libstlport_static.a -lgcc -no-canonical-prefixes -march=armv7-a -Wl,--fix-cortex-a8  -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -fPIE -pie   -lc -lm -o ./obj/local/armeabi-v7a/hello[armeabi-v7a] Install        : hello => libs/armeabi-v7a/hello
install -p ./obj/local/armeabi-v7a/hello ./libs/armeabi-v7a/hello
/cygdrive/d/development/android-ndk-r10d/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/bin/arm-linux-androideabi-strip --strip-unneeded ./libs/armeabi-v7a/hello

As we can see, ndk-build actually did the following things:

  1. Remove previously built files in the output folder libs.
  2. Build hello.o from the source code.
  3. Build executable from hello.o.
  4. Copy executable file to subfolders libs folder according to the ABI.

The above building information shows how the ndk-build invokes the toolchain to build the project. Basically, /cygdrive/d/development/android-ndk-r10d/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ is the standalone toolchain coming with the NDK installation. And if we read the whole command, we find that the command just invokes the cross-compilation version g++, with building parameters such as include path, library path and so on. The most straightforward way to use standalone toolchain is to mimic what ndk-build does, and directly invoke the right compilers based on your target architecture and platforms.

Under the NDK_ROOT/toolchains directory, we can find different toolchains for ARM, X86, X86_64, MIPS and so on. There are also versions with different compilers such as g++ and clang. Therefore, we can basically choose whatever is suitable for our projects.

3. Use customized toolchain for your projects

Apparently, the above method works, but it is very verbose and not suitable for larger projects. What we can do is to create a “customized” toolchain for a specific platform and ABI, with the help of a tool $NDK/build/tools/make-standalone-toolchain.sh provided with NDK installation.

Let’s look at an example. Assume we have a project with the following configurations:

  • Support android-19 platform.
  • Host system is Windows 7 64bit.
  • Target architecture is ARM.

We can create a script generate_standalone_toolchain.sh to help us export the toolchain we need:

generate_standalone_toolchain.sh

NDK=/cygdrive/d/development/android-ndk-r10d
SYSROOT=$NDK/platforms/android-19/arch-arm/
mkdir -p /cygdrive/d/development/standalone_toolchain/
$NDK/build/tools/make-standalone-toolchain.sh --arch=arm --platform=android-19 --system=windows-x86_64 --install-dir=/cygdrive/d/development/standalone_toolchain/
chmod -R 755 /cygdrive/d/development/standalone_toolchain

The helper script $NDK/build/tools/make-standalone-toolchain.sh creates a temporary directory under /tmp, copies files to that directory, and finally copies the files to the specified folder. Please make sure you have the enough permission, otherwise you will meet “permission denied” error when accessing the /tmp directory.

We should see the following console information if the path is configured correctly:

$ ./generate_standalone_toolchain.sh
Auto-config: --toolchain=arm-linux-androideabi-4.8
Copying prebuilt binaries...
Copying sysroot headers and libraries...
Copying c++ runtime headers and libraries...
Copying files to: /cygdrive/d/development/standalone_toolchain/
Cleaning up...
Done.

Once this is done, we can see the whole toolchain is copied from NDK_ROOT/toolchains to /cygdrive/d/development/standalone_toolchain/.

Example: helloworld

To test the customized toolchain, we create an example project helloworld. The project structure is very simple:

+-- helloworld
|   +-- hello.cpp
|   +-- Makefile

hello.cpp

#include <iostream>
int main()
{std::cout << "Hello World!" << std::endl;
}

Makefile

STANDALONE_TOOLCHAIN=/cygdrive/d/development/standalone_toolchain/bin/
CC=$(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-gcc
CXX=$(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-g++
CFLAGS=-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -c -Wall
LDFLAGS=-march=armv7-a -Wl,--fix-cortex-a8
SOURCES=hello.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=helloall: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS) $(CXX) $(LDFLAGS) $(OBJECTS) -o $@
.cpp.o:$(CXX) $(CFLAGS) $< -o $@clean: rm *.o hello;

We can simply compile the code as follows, and we will get executable files:

$ cd helloworld
$ make
/cygdrive/d/development/standalone_toolchain/bin//arm-linux-androideabi-g++ -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -c -Wall hello.cpp -o hello.o
/cygdrive/d/development/standalone_toolchain/bin//arm-linux-androideabi-g++ -march=armv7-a -Wl,--fix-cortex-a8 hello.o -o hello

Another example: clcompute

This is a more complicated example, which does parallel vector addition using OpenCL. Assume we have CL include and library files available:

+-- D:\opencl_lib
|   +-- include
|       +-- CL
|   +-- libs
|       +-- libOpenCL.so

The CL include header files can be downloaded from Khronos Group website. And the libOpenCL.so library file can be retrieved from an OpenCL-capable phone. You can use adb pull to pull it from your phone (or tablet). You can refer to the table in the part 1 of this article for the detailed position of the libOpenCL.so for different SoC chipsets.

The project structure:

+-- clcompute
|   +-- clcompute.cpp
|   +-- Makefile

Makefile

STANDALONE_TOOLCHAIN=/cygdrive/d/development/standalone_toolchain/bin/
OPENCL=/cygdrive/d/opencl_lib/
CC=$(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-gcc
CXX=$(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-g++
CFLAGS=-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -c -I $(OPENCL)/inc/
LDFLAGS=-march=armv7-a -Wl,--fix-cortex-a8 -L$(OPENCL)/libs/ -lOpenCLSOURCES=clcompute.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=clcomputeall: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS) $(CXX) $(LDFLAGS) $(OBJECTS) -o $@
.cpp.o:$(CXX) $(CFLAGS) $< -o $@clean: rm *.o $(EXECUTABLE);

As you can see, once you have exported the standalone toolchain, the makefile is basically the same as a normal makefile, once you have specified the path to your toolchain. We can imagine that by using the standalone toolchain, we can build some complicated projects which may require significant amount of effort is ndk-build was used.

4. Summary

In this technical note (part 1 and part 2), we have covered the usage and techniques related to the compilation of the Android native projects. Hope this article is useful, and if you have some better ideas or any comments, please feel free to leave your word below.

http://web.guohuiwang.com/technical-notes/androidndk2

Mastering Android NDK Build System - Part 2: Standalone toolchain相关推荐

  1. Mastering Android NDK Build System - Part 1: Techniques with ndk-build

    This article is not a "Hello world!"-type tutorial for NDK. Although I will still provide ...

  2. Android NDK: WARNING: Ignoring unknown import directory:错误解决方法

     Android NDK: WARNING: Ignoring unknown import directory:错误解决方法 添加NDK模块路径(参考,具体视情况): NDK_MODULE_PATH ...

  3. 【错误记录】Android NDK 错误排查记录 ( java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader )

    文章目录 一. 报错信息 二. 错误分析 三. 报错时使用的 Gradle 和 Gradle 插件版本的配置 四. 修改方案 五. 总体分析 一. 报错信息 报错信息 : 2020-06-14 12: ...

  4. Android NDK 获取手机部分信息 build.prop

    以下是 Android 手机  build.prop 信息,可同时在java 和 NDK获取到 下面是通过 adb shell cat /system/build.prop 获取到的信息 # begi ...

  5. Linux下编译build的命令,Linux命令行下编译Android NDK的示例代码

    这几天琢磨写一个Android的Runtime用来加速HTML5 Canvas,让GameBuilder+CanTK 不但开发速度快,运行速度也能接近原生应用.所以花了点时间研究Android NDK ...

  6. android ndk platform,Android NDK Platform Build and Application

    摘要: Since the launch of Android NDK,the official guide of its building process and application under ...

  7. android ndk standalone,Android NDK make-standalone-toolchain因mips而失败

    我正在运行make-standalone-toolchain.sh以使用以下命令为mips架构创建工具链: ./build/tools/make-standalone-toolchain.sh --p ...

  8. Android NDK开发之旅29 云服务器Ubuntu下搭建NDK环境,并编译FFmpeg

    ###前言 因为在Linux环境下编译FFmpeg生成库和头文件下比较方便,所以接下来主要操作在Linux环境下进行.但是对于Android NDK 开发新手来说,自己电脑配置Ubuntu Linux ...

  9. Android NDK基础样例

    Android NDK基础样例 NDK(Native Development Kit),用C/C++封装一些东西?好像就这么理解好了== 一.环境准备 这个好讨厌==!因为我环境都已经搭了很久了. 已 ...

最新文章

  1. 我们工作到底为了什么(坚持全篇看完你将受益匪浅)(转)
  2. java 中的 viewUtils框架
  3. SQLite简易入门
  4. 全球与中国节能冷却塔销售渠道分布及市场营销状况分析报告2022-2028年版
  5. ASP.NET真假分页—真分页
  6. ITK:遮盖一张图像给定标签图
  7. SAP Commerce Cloud 概述
  8. leetcode257. 二叉树的所有路径(两种做法)
  9. java学习(74):GUL面板
  10. 动态生成类_springboot动态生成类属性
  11. Kconfig内容(详细)总结附示例快速掌握
  12. Java练习题2-基础(含解析)
  13. 统计学三大相关系数之斯皮尔曼(spearman)相关系数
  14. 强化学习#code3
  15. 【绝对原创】EFS加密文件真的可以解密!各位不要放弃哈~
  16. 以下哪些是微型计算机,2017版计算机试题及答案
  17. 基于android的校园社区平台
  18. [转贴]汉武帝太子刘据的悲剧
  19. 【进阶Python】第一讲:开篇
  20. http://www.dewen.net.cn/q/17095/SQL:用一条SQL语句统计出符合条件的内容

热门文章

  1. [转]避免PHP-FPM内存泄漏导致内存耗尽
  2. Can't connect to MySQL server on 'localhost' 10061
  3. python input()与raw_input()
  4. Python学习笔记:面向对象高级编程(中下)
  5. Mathematica常用命令
  6. 一个操作系统的实现(1):分析linux下如何运行一个执行文件
  7. GPS-nmealib学习
  8. 一个不错的shell 脚本教程 入门级
  9. [云炬创业基础笔记]第六章商业模式测试23
  10. python编程标准_Python常见编程规范总结