How to build an executable for Android shell
The answer provides a sequence of steps for building an executable for Android shell
through both Eclipse
(outdated) and Android Studio
(4.1+ by the time of this writing). The last includes ndk-build
and CMake
.
I. PREPARE SOURCE CODE
As an example consider mycommand.c
:
#include <stdio.h>
int main()
{
printf("My Command!\n");
return 0;
}
II. BUILD EXECUTABLE
Eclipse (might be outdated)
In assumption that NDK
location is set in Eclipse
, create a new Android Application Project
and do the following steps.
Add native support. Right click on the project in
Project Explorer
>Android Tools
>Add Native Support
>Finish
Add source code, i.e. put
mycommand.c
underproject_root
/jni
folder.Edit
Android.mk
underproject_root
/jni
as follows:LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mycommand
LOCAL_SRC_FILES := mycommand.c
include $(BUILD_EXECUTABLE)Create
Application.mk
* under theproject_root
/jni
folder:APP_ABI := all
Build executable and find it under
project_root/libs/<abi>/mycommand
.
*Binaries for all
supported CPU architectures are generated here. Use adb shell cat /proc/cpuinfo
to find out the CPU architecture and set APP_ABI
as per Supported ABIs.
Android Studio and ndk-build
The steps are as follows.
Add
mycommand.c
,Android.mk
(same as in theEclipse
section above) to the/app/src/main/cpp
folder.Edit
build.gradle
:android {
...
defaultConfig {
...
externalNativeBuild {
ndkBuild {
targets "mycommand"
// use a specific ABI filter if needed
// abiFilters "armeabi-v7a"
}
}
}
externalNativeBuild {
ndkBuild {
path "src/main/cpp/Android.mk"
}
}
}Build project and find the executable under
/app/.externalNativeBuild/ndkBuild/debug/obj/local/<abi>/mycommand
Android Studio and CMake
Create a project using the Native C++ template.
Add
mycommand.c
to the/app/src/main/cpp
folder and editCMakeLists.txt
:cmake_minimum_required(VERSION x.x.x)
add_executable(mycommand
mycommand.c )Edit
build.gradle
:android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
targets "mycommand"
// use a specific ABI filter if needed
// abiFilters "armeabi-v7a"
}
}
}
...
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
}Build project and find the executable under
/app/build/intermediates/cmake/debug/obj/<abi>/mycommand
III. PUSH BINARY INTO DEVICE
Push mycommand
binary from where it is located into your device. Keep in mind that files on SD card aren't executable by default, so the binary should be pushed into the device's internal storage. Depending of whether device is rooted or not you have the following options:
On non-rooted device you can push the binary to
/data/local/tmp
:adb push mycommand /data/local/tmp
On rooted device you can push the binary to SD card and then copy it to
/system/bin
(after remounting the partition in read-write mode) along with the other executable files:adb push mycommand /path/to/sdcard
adb shell
su
mount -o rw,remount /system
cp /path/to/sdcard/mycommand /system/bin
IV. SET EXECUTABLE PERMISSION (optional)
Set the permission of the binary to be executable (this might not be needed in case of /data/local/tmp
). Below chmod 555
(r-xr-xr-x) is used:
adb shell chmod 555 /path/to/mycommand
V. RUN COMMAND
Now you can shell into your device (with adb shell
) and execute the command.
On non-rooted device use the absolute path to the command:
$ /data/local/tmp/mycommand
My Command!On rooted device, in case the binary has been copied to
/system/bin
, you can call it by the file name:$ mycommand
My Command!
Running executable from Android shell
If running the executable with a full path to it doesn't work, the problem might be with the executable itself, meaning it either
- wasn't successfully compiled, or
- was compiled for another CPU, not the one your device had.
In this case the options you have are as follows:
- if you have access to the source code, compile it for your device's ABI,
- if it is a 3rd party executable, ask for an executable compiled for your device's ABI (or, if possible, find it yourself).
How to create an Android executable for launch from the shell?
For me, I didn't need eclipse nor any java code in my application. My application that was being ported from Linux, already had a set of makefiles already in place. I was able to use my existing makefile system by way of the standalone tool chain portion of the NDK.
This answer got me going with the standalone tool chain. In my case, here is how I invoked it where I am cross compiling from my Macintosh, having already installed the NDK at /Users/me/Development/android-ndk-r10d
:
ANDROID_NDK=/Users/me/Development/android-ndk-r10d
SYSROOT=$(ANDROID_NDK)/platforms/android-19/arch-arm
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh --platform=android-19 --install-dir=${ANDROID_NDK}/myapp-android-toolchain --ndk-dir=/Users/me/Development/android-ndk-r10d --toolchain=arm-linux-androideabi-4.8 --system=darwin-x86_64
With this setup, I launched my build like this:
cd ~/base/of/myapp/src/
ANDROID_NDK=/Users/me/Development/android-ndk-r10d PATH=${ANDROID_NDK}/myapp-android-toolchain/bin:$PATH make
After I fixed some issues with config for my cross-compilation in some third-party libraries I'm using, I had a working build. Next, I wanted to install it on my phone:
# Push to a location with write permission (sdcard):
cd ~/base/of/myapp/bin/ # My build puts the executable here.
adb push myapp /sdcard/
# Go into phone and complete the install manually:
adb shell
su
mount -oremount,rw rootfs /system # /vendor/bin is in /system mount.
# One time creation of /vendor/bin (that is in the PATH by default):
mkdir /vendor/bin
# Copy the myapp executable over
cp /sdcard/myapp /vendor/bin/myapp
Now, I can invoke myapp from the shell on my phone, like a normal command line interface Linux application. The argc
and argv
from my original Linux code work as written in the Android build by this process.
How do I build a native (command line) executable to run on Android?
As of NDK r8d, this can be solved in a much simpler way.
Create a project with the following directory hierarchy:
project/
jni/
Android.mk
Application.mk
*.c, *.cpp, *.h, etc.Fill in Android.mk with the following content. The most important thing is the last line. Check the NDK doc for the meaning of the other variables.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := name-of-your-executable
LOCAL_SRC_FILES := a.cpp b.cpp c.cpp etc.cpp
LOCAL_CPPFLAGS := -std=gnu++0x -Wall -fPIE # whatever g++ flags you like
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -fPIE -pie # whatever ld flags you like
include $(BUILD_EXECUTABLE) # <-- Use this to build an executable.Go to the
project/
directory, and simply typendk-build
The result will be placed in
project/libs/<arch>/name-of-your-executable
.
Android shell don't find the file to execute
Your executable is missing a library. The most likely reason is that you just built a Linux ARM executable (not an Android one) which is linked against some libc
version other than Android Bionic.
You could either learn how to build proper Android executables or a statically linked binary might just work for your purpose.
Compile and run C code for Android
Let's start from the bottom up.
Going C (or C++) does not grant your code extra rights under Android.
There are different options of doing all your development without Java. There are frameworks for pure C++ (like NativeActivity), or for C# (MonoDroid), or Scala, or Ruby, or whatnot.
Android NDK also allows to simply build an executable - one that can be run from command line, and has no GUI. Your Android app can launch such executable via standard Java Runtime.exec()
and her siblings. Or you can launch this executable from a terminal emulator or adb shell
.
If you have root access on your device (or if you flash your own mod), you can launch an executable through the standard Linux init.rc
or similar.
Note that in the latter case, you can easily grant your executable root
or other permissions.
Related Topics
Error Android Emulator Gets Killed in Android Studio
Get Content Uri from File Path in Android
How to Implement Recyclerview with Cardview Rows in a Fragment with Tablayout
How to Serialize an Object and Save It to a File in Android
Switching Between Android Navigation Drawer Image and Up Caret When Using Fragments
How to Know an Application Is Installed from Google Play or Side-Load
How to Get the First Name and Last Name from Android Contacts
Android: Access Child Views from a Listview
Error:(6, 0) Gradle Dsl Method Not Found: 'Google()'
Calculate Compass Bearing/Heading to Location in Android
Calling Activity Class Method from Service Class
This Version of the Application Is Not Configured for Billing Through Google Play
Google Sign in Not Working After Publishing in Play Store
How to Add a Custom Button State
Start_Sticky Does Not Work on Android Kitkat
How to Determine If a Firebase User Is Signed in Using Facebook Authentication