Android Development in C: Difference between revisions

From MK Wiki EN
Jump to navigation Jump to search
(Ubuntu 18.04 Bionic)
 
(4 intermediate revisions by the same user not shown)
Line 11: Line 11:
* binutils-arm-linux-gnueabi (recommended)
* binutils-arm-linux-gnueabi (recommended)


The program adb is required for communicating with the Android device. Package: android-tools-adb - Documentation can be found [http://developer.android.com/tools/help/adb.html here].
The program <code>adb</code> is required for communicating with the Android device. Package: android-tools-adb - Documentation can be found [http://developer.android.com/tools/help/adb.html here].


=== Troubleshooting adb ===
=== Troubleshooting adb ===
Line 24: Line 24:


[http://stackoverflow.com/questions/14460656/android-debug-bridge-adb-device-no-permissions?answertab=oldest#answer-15043526 Credits]
[http://stackoverflow.com/questions/14460656/android-debug-bridge-adb-device-no-permissions?answertab=oldest#answer-15043526 Credits]
=== Troubleshooting execution ===
==== file ====
By using the <code>file</code> command it is possible to determine if the binary was made for the target platform (ARM v7 in my case).
Example output:
base32: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=0aedb66bd001b21993435dc6252feef208fe2810, with debug_info, not stripped
==== Used Libraries ====
Commands such as <code>arm-linux-gnueabi-readelf</code> or <code>arm-linux-gnueabi-objdump</code> can be used to see which libraries a program depends on ([https://stackoverflow.com/questions/6150000/cross-compiler-ldd Credits]). Prepend them with <code>LANG=C</code> if your system is set to a language other than English.
arm-linux-gnueabi-readelf -a base32 | grep "Shared library:"
'''Example output:'''
0x00000001 (NEEDED)                    Shared library: [libc.so.6]
0x00000001 (NEEDED)                    Shared library: [ld-linux.so.3]
arm-linux-gnueabi-objdump -x base32 | grep NEEDED
'''Example output:'''
NEEDED              libc.so.6
NEEDED              ld-linux.so.3
If libraries are missing they can be copied from another system. By installing the package [https://packages.ubuntu.com/libc6-armel-cross libc6-armel-cross] they can be found in <code>/usr/arm-linux-gnueabi/lib</code>.


=== Mounting /system read-write ===
=== Mounting /system read-write ===
Line 96: Line 126:
=== Downloading ===
=== Downloading ===


I am developing on Ubuntu 18.04 Bionic which ships with coreutils 8.28. coreutils have a lot of dependencies (like autoconf, autopoint, patch...), so to keep things simple, I grab the sources that match my operating system's version: [hhttps://launchpad.net/ubuntu/+archive/primary/+sourcefiles/coreutils/8.28-1ubuntu1/coreutils_8.28.orig.tar.xz coreutils_8.28.orig.tar.xz 5.0 MiB] [https://launchpad.net/ubuntu/+source/coreutils/8.28-1ubuntu1 Download page]
I am developing on Ubuntu 14.04 which ships with coreutils 8.21. coreutils have a lot of dependencies (like autoconf, autopoint, patch...), so to keep things simple, I grab the sources that match my operating system's version: [https://launchpad.net/ubuntu/+archive/primary/+files/coreutils_8.21.orig.tar.gz coreutils_8.21.orig.tar.gz 11.7 MiB] [https://launchpad.net/ubuntu/+source/coreutils/8.21-1ubuntu5.4 Download page]


=== Customizing ===
=== Customizing ===


After extracting the files from that archive, I do a "./configure" in the directory that contains the files. This process takes about 1 min 45 sec. After that it is important to customize the "Makefile": Search for a line containing
After extracting the files from that archive, I do a "./configure" in the directory that contains the files. This process takes about 45 sec on my 6-core CPU. After that it is important to customize the "Makefile": Search for a line containing


  CC = gcc -std=gnu99
  CC = gcc -std=gnu99
Line 106: Line 136:
and replace it by
and replace it by


  CC = arm-linux-gnueabi-gcc -std=gnu99 -static
  CC = arm-linux-gnueabi-gcc
CPP = arm-linux-gnueabi-g++
 
if the system has the "/lib" link described above. Otherwise these lines should read
 
CC = arm-linux-gnueabi-gcc -static
CPP = arm-linux-gnueabi-g++ -static
 
but be aware that the binaries will have a much greater size then.


Why "-static"? Otherwise the programs get linked dynamically, so they depend on the loader to resolve linked libraries. When testing on my Ubuntu machine, it was no problem:
Why "-static"? Otherwise the programs get linked dynamically, so they depend on the loader to resolve linked libraries. When testing on my Ubuntu machine, it was no problem:
Line 112: Line 150:
  qemu-arm -L /usr/arm-linux-gnueabi/ '''program'''
  qemu-arm -L /usr/arm-linux-gnueabi/ '''program'''


However, on my destination device running Cyanogenmod 9, I always get a "No such file or directory" error when trying to run those files.
However, on my destination device running Cyanogenmod 9, I always get a "No such file or directory" error when trying to run those files (unless "/lib" does not exist, see above).


=== Building ===
=== Building ===
Line 125: Line 163:
  src/sleep: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=06a81ace0e2dabd5491dea6923ce0832295ba3f8, not stripped
  src/sleep: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=06a81ace0e2dabd5491dea6923ce0832295ba3f8, not stripped


=== Problems ===
On my Ubuntu 18.04 system I cannot build coreutils for my Cyanogenmod device. Compiling coreutils 8.21 fails with this message:
<pre>
  CC    lib/set-mode-acl.o
In file included from /usr/arm-linux-gnueabi/include/libintl.h:103:0,
                from lib/gettext.h:25,
                from lib/set-mode-acl.c:28:
./lib/locale.h:50:11: fatal error: xlocale.h: No such file or directory
# include <xlocale.h>
          ^
compilation terminated.
</pre>
Installing package libc++-dev, which supposedly provides the file xlocale.h, did not work.
Compiling coreutils 8.28 generally works (except the part of the man page creation because this requires execution of the binaries which would not work on my x64 system), but the binaries cannot be executed on my target device because its kernel is too old (2.6.32.9-FXP).


[[Category:Android]]
[[Category:Android]]
[[Category:Linux]]
[[Category:Linux]]
[[Category:Programming]]
[[Category:Programming]]

Latest revision as of 18:17, 4 February 2022

This article just describes how to build a simple terminal application in C and C++ that finally runs on an Android device. GUI development is not addressed.

Prerequisites

Packages required/recommended for ARM development in C

Most Android devices are equipped with a APU utilizing ARM architecture. Therefore, binaries for ARM must be created. The following packages must be used on Debian systems to install compilers for C and C++:

  • gcc-arm-linux-gnueabi
  • g++-arm-linux-gnueabi
  • binutils-arm-linux-gnueabi (recommended)

The program adb is required for communicating with the Android device. Package: android-tools-adb - Documentation can be found here.

Troubleshooting adb

If "adb devices" returns "???????????? no permissions", the following commands can help:

adb kill-server && adb start-server

This should be executed as root.

Credits

Troubleshooting execution

file

By using the file command it is possible to determine if the binary was made for the target platform (ARM v7 in my case).

Example output:

base32: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=0aedb66bd001b21993435dc6252feef208fe2810, with debug_info, not stripped

Used Libraries

Commands such as arm-linux-gnueabi-readelf or arm-linux-gnueabi-objdump can be used to see which libraries a program depends on (Credits). Prepend them with LANG=C if your system is set to a language other than English.

arm-linux-gnueabi-readelf -a base32 | grep "Shared library:"

Example output:

0x00000001 (NEEDED)                     Shared library: [libc.so.6]
0x00000001 (NEEDED)                     Shared library: [ld-linux.so.3]
arm-linux-gnueabi-objdump -x base32 | grep NEEDED

Example output:

NEEDED               libc.so.6
NEEDED               ld-linux.so.3

If libraries are missing they can be copied from another system. By installing the package libc6-armel-cross they can be found in /usr/arm-linux-gnueabi/lib.

Mounting /system read-write

That's required to write binaries to /system/bin so they can be executed. Normally, /sdcard is mounted with noexec option, hence it doesn't qualify for starting binaries from there.

mount -o rw,remount /system

Terminal emulator on Android device

A terminal emulator can be used on the device to start programs.

Hello World example in C

helloworld.c

#include <stdio.h>

int main(int argc, char** argv) {
   printf("Hello world!\n");
   return 0;
}

Building and deploying

arm-linux-gnueabi-gcc helloworld.c -o helloworld

This requires the destination system to have a symbol link /lib to /system/lib. If this is not yet the case and can be done (i.e., root access is available):

mount -o rw,remount /
ln -s /system/lib/ lib

Otherwise the program can be linked statically:

arm-linux-gnueabi-gcc -static helloworld.c -o helloworld

The size difference is 8040 bytes for the dynamically linked version and 589 534 bytes (576 KiB) for the statically linked version.

Finally, the binary can be stored on the destination system:

adb push helloworld /system/bin

Running

Either with adb shell /system/bin/helloworld or by executing it on the device using a terminal emulator.

Hello World example in C++

helloworldcpp.c++

#include <iostream>
using namespace std;
int main (int argc, char **argv)
{
	cout << "Hello World from C++!" << endl;
}

Building and deploying

arm-linux-gnueabi-g++ -static helloworldcpp.c++ -o helloworldcpp
adb shell /system/bin/helloworldcpp

Compiling GNU coreutils

Downloading

I am developing on Ubuntu 14.04 which ships with coreutils 8.21. coreutils have a lot of dependencies (like autoconf, autopoint, patch...), so to keep things simple, I grab the sources that match my operating system's version: coreutils_8.21.orig.tar.gz 11.7 MiB Download page

Customizing

After extracting the files from that archive, I do a "./configure" in the directory that contains the files. This process takes about 45 sec on my 6-core CPU. After that it is important to customize the "Makefile": Search for a line containing

CC = gcc -std=gnu99

and replace it by

CC = arm-linux-gnueabi-gcc
CPP = arm-linux-gnueabi-g++

if the system has the "/lib" link described above. Otherwise these lines should read

CC = arm-linux-gnueabi-gcc -static
CPP = arm-linux-gnueabi-g++ -static

but be aware that the binaries will have a much greater size then.

Why "-static"? Otherwise the programs get linked dynamically, so they depend on the loader to resolve linked libraries. When testing on my Ubuntu machine, it was no problem:

qemu-arm -L /usr/arm-linux-gnueabi/ program

However, on my destination device running Cyanogenmod 9, I always get a "No such file or directory" error when trying to run those files (unless "/lib" does not exist, see above).

Building

After doing a "make" - which runs about 2 min 30 sec - everything works fine. If you want to test if a program was linked statically or dynamically, use the file program:

file program

Example output:

$ file src/sleep
src/sleep: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=06a81ace0e2dabd5491dea6923ce0832295ba3f8, not stripped

Problems

On my Ubuntu 18.04 system I cannot build coreutils for my Cyanogenmod device. Compiling coreutils 8.21 fails with this message:

  CC     lib/set-mode-acl.o
In file included from /usr/arm-linux-gnueabi/include/libintl.h:103:0,
                 from lib/gettext.h:25,
                 from lib/set-mode-acl.c:28:
./lib/locale.h:50:11: fatal error: xlocale.h: No such file or directory
 # include <xlocale.h>
           ^
compilation terminated.

Installing package libc++-dev, which supposedly provides the file xlocale.h, did not work.

Compiling coreutils 8.28 generally works (except the part of the man page creation because this requires execution of the binaries which would not work on my x64 system), but the binaries cannot be executed on my target device because its kernel is too old (2.6.32.9-FXP).