Android Development in C: Difference between revisions

From MK Wiki EN
Jump to navigation Jump to search
(Downloading: Reverting back to old version (Ubuntu 14.04, coreutils 8.21))
 
Line 163: 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).