Thursday, March 10, 2016

How to compile libpng using Android NDK?

To build libpng 1.6.28 with Android Studio 2.2 based tools like CMake, Ninja please look at this article.

http://www.ourinnovativemind.in/2017/02/new-building-libpng-1628-using-android.html



Below method uses ndk-build to build libpng.


This page is for you if want to compile libpng for Android or just got a warning mail from Google PlayStore regading libpng vulnerability issue of old versions. "Google Play warning: You are using vulnerable version of libpng". This article/tutorial is about compiling libpng 1..6.19 for Android.



My setup:
  • OpenSuse Linux Leap 42.1.20151028 x86_64 (64Bit), AMD Athlon X2
  • Android NDK r10e-rc4 (64-bit). Directory name android-ndk-r10e-linux
  • Terminal / Bash shell. On Windows one needs to install binutils, development environment. Just install CodeBlocks windows or other such compiler. They contain most of needed tools.


Because my setup is Linux with disk limit due to 128GB SSD i have not installed 2 set of tools for each OS i.e. Linux and Windows. However it will not take more than minute to change the scripts to Windows. Most of my scripts are hard-coded for 64Bit Linux. Kindly change the variables to your NDK to let the scripts run bug free. Or for a person who just needs Android.mk file simply copy the content from end of this article.


Starting steps:
  • Download Android NDK and extract/install to a path without containing space or special characters. If using Linux then make symbolic link to home.
  • Download libpng version 1.6.19 (November 12, 2015)
  • Create a working directory where libpng will be compiled. Extract libpng.

Extracted libpng contains many files like README, TODO etc. One should read them as they contain important information. Before compiling libpng must be made aware of where compiler, other compiler related tools, headers and objects (compiled code) are saved. This information is collected by configure script. If interested open “configure” file in text editor and scroll to end. There are below lines -



# Assembler program.
AS=$lt_AS


# DLL creation program.
DLLTOOL=$lt_DLLTOOL

# Object dumper program.
OBJDUMP=$lt_OBJDUMP

# Whether or not to build shared libraries.
build_libtool_libs=$enable_shared

# The PATH separator for the build system.
PATH_SEPARATOR=$lt_PATH_SEPARATOR

# The host system.
host_alias=$host_alias
host=$host
host_os=$host_os



SED, GREP, FGREP, ECHO etc near end of file. These are the stuff configure script requires to build the final Makefile. We have to provide these things to configure script. After I started building libraries like libpng, FreeType, ImageMagick, GraphicsMagick etc for Android I collected some scripts from various sources like stackoverflow and build this script. It contains some hard-coded values but that takes minute to change as per system.


If project is small and contains few files we can build source without configure script or even Makefile. It is recommended that we understand the basics of this system. For example look at scripts directory there are many makefile.PLATFORM files where PLATFORM = msys, linux etc. We can use those makefiles to build a working Makefile or get information about build flags etc. But that's not easier than configure script.


Android Script

# AndroidBuild.sh START
#!/bin/sh
# remove flag for non neon ARM processors.

export HAS_NEON="--enable-arm-neon"
export CONFIGURATION_OPTIONS="--disable-shared $HAS_NEON"

# use custom build environment
# installation directory
export PREFIX=`pwd`/prefix

# Path of NDK. For simplicity make symlinks in home directories
export NDK=/mnt/work/SDK_IDE/android-ndk-r10e-linux/

#export NDK=/home/bindesh/bin/ndk (SYMLINK)
# processor specific libraries and includes.
# Suffix for arch-???. arch-arm arch-arm64 arch-mips arch-mips64 arch-x86 arch-x86_64
export ARCH=arm
 

# compiler for processor
export CROSS_COMPILE=arm-linux-androideabi

# Android platform version
export PLATFORM=android-8

# GCC compiler version
export GCC_VERSION=4.8

# Getting toolchain directory inside NDK from variables set above
# Hardcoded for linux running on x86 cpu 64-Bit
export ANDROID_PREFIX=${NDK}/toolchains/$CROSS_COMPILE-$GCC_VERSION/prebuilt/linux-x86_64

# SYSROOT. usr dir i.e. usr/include, usr/lib
export SYSROOT=${NDK}/platforms/$PLATFORM/arch-$ARCH
export CROSS_PATH=${ANDROID_PREFIX}/bin/${CROSS_COMPILE}

# Some compiler and binutils. More might be needed depending on source.
export CPP=${CROSS_PATH}-cpp
export AR=${CROSS_PATH}-ar
export AS=${CROSS_PATH}-as
export NM=${CROSS_PATH}-nm
export CC=${CROSS_PATH}-gcc
export CXX=${CROSS_PATH}-g++
export LD=${CROSS_PATH}-ld
export RANLIB=${CROSS_PATH}-ranlib

# package configuration file save location
export PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig

# Flags for compiler
export CFLAGS="${CFLAGS} --sysroot=${SYSROOT} -I${SYSROOT}/usr/include -I${ANDROID_PREFIX}/include"

export CPPFLAGS="${CFLAGS}"
export LDFLAGS="${LDFLAGS} -L${SYSROOT}/usr/lib -L${ANDROID_PREFIX}/lib"

./configure --host=${CROSS_COMPILE} --with-sysroot=${SYSROOT} --prefix=${PREFIX} "$@" $CONFIGURATION_OPTIONS

make
make install
 

# AndroidBuild.sh END



Copy all lines above and paste in a new file AndroidBuild.sh and save. Then change the variables valid for your system. Create folder prefix or whatever name you like. Change NDK=/mnt/work/SDK_IDE/android-ndk-r10e-linux/ and compiler related values as per your system. This script copied from web can cause error due to removal of newlines for strange reasons. Ensure # is ahead of comments.

Now run sh AndroidBuild.sh. It should end without errors. This will install all built files in prefix directory. Now we can copy libpng16.a renamed to libpng.a and headers directory.

Links: Script file http://txt.do/5vb70 Or http://textuploader.com/5vb70


Above script is common to most of tasks and is best for building most of C libraries. To add C++support more variables are needed. Some possible errors:

  • Error in running compiler tools. This can be due to incorrect final paths of build tools. Look at config.log and cross check if resulting paths are correct.
  • Error in finding libraries. This can be because of wrong names of libraries and -l parameter to compiler. Ensure path and names are correct. Configure script runs a lot of tests which tests each used libraries with a small sample code. Check the results of these sample codes in config.log.

If everything seems not working then ensure the installation of tools is correct and they do their job. Make simple programs and test them. Test NDK with Android Studio or Eclipse. Do these types of tests. I myself have spent time frustrated with these types of problems. In Linux i even suffered problems like executable flag of executable files were removed due to unknown reason!.



Android.mk


LOCAL_PATH := $(call my-dir)

# $(call my-dir) return path of this Android.mk directory

PNG_SRC_PATH    :=
INC_PNG                := $(LOCAL_PATH)/


include $(CLEAR_VARS)

LOCAL_MODULE    := libpng
LOCAL_CFLAGS    :=
LOCAL_CPPFLAGS  := ${LOCAL_CFLAGS}

LOCAL_C_INCLUDES  :=  \
    ${INC_PNG} \
       
LOCAL_SRC_FILES := \
    ${PNG_SRC_PATH}pngerror.c \
    ${PNG_SRC_PATH}pngwio.c \
    ${PNG_SRC_PATH}pngwrite.c \
    ${PNG_SRC_PATH}pngwutil.c \
    ${PNG_SRC_PATH}pngwtran.c \
    ${PNG_SRC_PATH}pngset.c \
    ${PNG_SRC_PATH}pngtrans.c \
    ${PNG_SRC_PATH}example.c \
    ${PNG_SRC_PATH}png.c \
    ${PNG_SRC_PATH}pngrtran.c \
    ${PNG_SRC_PATH}pngmem.c \
    ${PNG_SRC_PATH}pngpread.c \
    ${PNG_SRC_PATH}pngrutil.c \
    ${PNG_SRC_PATH}pngrio.c \
    ${PNG_SRC_PATH}pngget.c \
    ${PNG_SRC_PATH}pngread.c
   
   
   

ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)

  LOCAL_SRC_FILES += ${PNG_SRC_PATH}arm/arm_init.c
  LOCAL_SRC_FILES += ${PNG_SRC_PATH}arm/filter_neon.S
  LOCAL_SRC_FILES += ${PNG_SRC_PATH}arm/filter_neon_intrinsics.c
endif


LOCAL_LDLIBS    := -llog -L../lib
# -lz -lm

include $(BUILD_STATIC_LIBRARY)