I’ve limited love to Android tools provided by Google and never understood why Google tries to make it so complicated to run native code on the device. In the end Android is some form of Linux and some parts of Android framework are implemented in C/C++
. I also have limited love (and knowledge) to Java and don’t really like to use it.
Anyways, here below I present 2 methods of compiling C programs with Android NDK.
Let’s use standard “hello world” as an application that we want to run on Android dev board (main.c
):
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
Method 1: Using ndk-build
This method follows Android’ic way of doing things:
-
Create required directories
mkdir -p hello_world/jni mkdir -p hello_world/libs
In the jni
directory create
-
Android.mk
-
Copy/create
main.c
tojni
directory -
Go to
jni
directory, callndk-build
. Compilation result should be inhello_world/libs/armeabi/hello_world
Method 2: Makefile
With the second (and my prefered) way you have better control over files being compiled, compiler settings, etc. There is also no “magic” that ndk-build
provides.
Following Makefile uses clang
from NDK 16b
in order to compile a file for Android with API version 27 and for ARMv8 CPU. The makefile can be used a template.
1# Change this to whereever you keep NDK
2NDK = /opt/android-ndk
3SRCDIR = .
4OBJDIR = .
5DBG ?= 0
6
7# Debug/Release configuration
8ifeq ($(DBG),1)
9MODE_FLAGS = -DDEBUG -g -O0
10else
11MODE_FLAGS = -Os -fdata-sections -ffunction-sections
12endif
13
14## NDK configuration (clang)
15
16# NDK Version
17NDK_TARGETVER = 27
18
19# Target arch - here aarch64 for android
20NDK_TARGETARCH = aarch64-linux-android
21
22# Target CPU (ARMv8)
23NDK_TARGETSHORTARCH = arm64
24
25# Toolchain version
26NDK_TOOLVER = 4.9
27
28# Architecture of a machine that does cross compilation
29NDK_HOSTARCH = linux-x86_64
30
31# Set needed preprocessor symbols
32NDK_TOOLS = $(NDK)/toolchains/llvm/prebuilt/$(NDK_HOSTARCH)/bin
33NDK_SYSROOT = $(NDK)/sysroot
34NDK_TOOL = $(NDK_TOOLS)/clang
35NDK_LIBS = $(NDK)/toolchains/$(NDK_TARGETARCH)-$(NDK_TOOLVER)/prebuilt/linux-x86_64/lib/gcc/$(NDK_TARGETARCH)/4.9.x
36NDK_INCLUDES = -I$(NDK)/sysroot/usr/include \
37 -I$(NDK)/sysroot/usr/include/$(NDK_TARGETARCH)
38NDK_SYSROOT = $(NDK)/platforms/android-$(NDK_TARGETVER)/arch-$(NDK_TARGETSHORTARCH)
39
40# Options common to compiler and linker
41OPT = $(MODE_FLAGS) \
42 -std=c99 \
43 -fPIE \
44 -Wall \
45 -target $(NDK_TARGETARCH)
46
47# Compiler options
48CFLAGS = $(OPT) \
49 $(NDK_INCLUDES)
50
51# Linker options
52LDFLAGS = $(OPT) \
53 $(MODE_FLAGS) \
54 -pie \
55 --sysroot=$(NDK_SYSROOT) \
56 -B $(ANDROID_NDK)/toolchains/$(NDK_TARGETARCH)-$(NDK_TOOLVER)/prebuilt/linux-x86_64/$(NDK_TARGETARCH)/bin \
57 -L$(NDK_LIBS)
58
59all:
60 $(NDK_TOOL) -c $(SRCDIR)/main.c -o $(OBJDIR)/main.o $(CFLAGS)
61 $(NDK_TOOL) -o main $(OBJDIR)/main.o $(LDFLAGS)
62
63adb-prepare:
64 adb root
65 adb remount
66
67push: adb-prepare
68 adb push main /data/app/
69
70run: adb-prepare push
71 adb shell /data/app/main
Copy this file to same directory as main.c
and try
This should compile the file, push it to target and run (if target is connected).
hdc@cryptoden 23:49 > ~/example
> make run
adb root
adb remount
remount succeeded
adb push main /data/app/
main: 1 file pushed. 0.7 MB/s (6000 bytes in 0.008s)
adb shell /data/app/main
Hello World