Compile C/C++ ARM binary (Static Library) for Android using Standalone toolchain

This post is intended for those who wants to compile and reuse their existing C/C++ code or who wants to compile an open source code for their Android applications. The idea came into my mind after putting time and effort for compiling and using an open source library CS-MAP in Android application. Hopefully this will help you to save a lot of time and efforts.

Android NDK provides set of tools for compiling and using C and/or C++ source files and generate the native ARM binaries (static, shared and executable) on Linux, OS X and Windows, which can be further used in Android application through Java Native Interface (JNI) calls.
I will explain how we can use the standalone cross-compilers for creating ARM binary (a static library) from C++ source files.

Step 1: Extract the standalone cross-compiler toolchain.

  • Install ANDROID-NDK from http://developer.android.com/sdk/ndk/index.html
  • Add an environment variable NDK and add path of NDK root directory as its value.
  • Run the script for extracting android NDK standalone toolchain binaries and other stuff.                                                                                                                                $NDK/build/tools/make-standalone-toolchain.sh –platform=android-14 –install-dir = /cygdrive/e/android/standalone-14

The above script creates a directory name “standalone-14” in “E:\android\” directory of my Window box

Note: As I am extracting the toolchain on Windows Box, so I passed the /cygwin/e/android/standalone-14 in my install directory path. For Linux and OS X one need to customize the above command accordingly.

Step 2: Identify the C/C++ Sources for compilation

  • Create a project directory having name “StaticLibraryTest
  • Create a source directory having name “src” in StaticLibraryTest directory which contains the C/C++ source files
  • Test1.cpp

// Contents of Test1.cpp
#include "Test1.h"
int  test1(int  x, int  y){
int temp = 44;
return (x + y )+ temp ;
}

  • Test2.cpp

// Content of Test2.cpp
#include "Test2.h"
int  test2(int  x, int  y, int z){
int temp = 9;
return (x * y) - temp + z;
}

  • Create a header directory having name “include” in StaticLibraryTest directory which contains the C/C++ header files
    • Test1.h

// Contents of Test1.h
#ifndef TEST1_H
#define TEST1_H
extern int test1(int  x, int  y);
#endif /* TEST1_H */

  • Test2.h

// Contents of Test2.h
#ifndef TEST2_H
#define TEST2_H
extern int test2(int  x, int  y, int z);
#endif /* TEST2_H */

Step 3: Create a make file for building the source and create static library

  • Create a file having name “make-static-library.mak” in “src” directory. This directory also contains the C/C++ source files. The content of make script are given below.


# This variable contains the path of bin directory which contains all the gnu tools required for compilation
# I have extracted the standalone toolchain for Android platform 14 in "e:\android\standalone-14"
ANDROID_NDK_BIN:=/cygdrive/e/android/standalone-14/bin
# Compilation Tools
CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc
CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++
AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar
# Compiler flags
# Specify all the flags below which you want to use for your compilation, For this simple example, we only need to specify the include directory path
CFLAGS          := -I../include
# Rule for making C++ object file
.cpp.o:
$(CPP) $(CFLAGS) -c  $<
# Rule for making C object file
.c.o:
$(CC) $(CFLAGS) -c  $<
STATIC_LIB_SRC = Test1.cpp \
Test2.cpp
STATIC_LIB_OBJ = Test1.o \
Test2.o
OUT = ccStaticLib.a
$(OUT): $(STATIC_LIB_OBJ)
$(AR) -crs $(OUT) $(STATIC_LIB_OBJ)

Step 4: Compilation using the make script

  • Open the console (Cygwin for Windows) and change the directory to the “src” directory which contains the C/C++ source files (Test1.cpp and Test2.cpp) and the make file (make-static-library.mak)
  • Execute the following command to compile the sources and generate the static library from these sources. “make –f make-static-library.mak

This will create the static library in the src directory name “ccStaticLib.a”. I have added the “cc” (Cross Compiler) as prefix in the name of static Library generated from make script.

Now static library “ccStaticLib.a” (ARM Binary for Android) is created and our next mission is to use this static library in Android project.

In my upcoming post I will share how we can use this in an Android project.

Updated code part to monospace font as suggested by Venkatesh Shukla.

This entry was posted in Android, C-C++, Cross-Compilation, Mobile and tagged , , , , , , . Bookmark the permalink.

29 Responses to Compile C/C++ ARM binary (Static Library) for Android using Standalone toolchain

  1. ukhan says:

    Hi,

    Excellent and a much needed tutorial. Thank you for posting. I followed your tutorial and I am getting an error:

    make-static-library.mak:17: *** missing separator. Stop.

    Appreciate any help. Thanks

    • tariqzubairy says:

      Problem with your make file at line 17. You need to add a TAB where you find this error. Please let me know if it still does not works for you

      • Vinod Jaiswal says:

        Hi,

        I have followed the tutorial and getting a error on line 13.
        make-static-library.mak:13: *** missing separator. Stop.
        Help would be appreciated.

        Thanks.

  2. Oleg says:

    Hello,
    Cool and clear tuturail, builded from first atemp.
    Thanks

  3. Hello When i build this i am getting following error.

    $ make -f make-static-library.mak
    g++ -c -o Test1.o Test1.cpp
    Test1.cpp:7:19: fatal error: Test1.h: No such file or directory
    compilation terminated.
    : recipe for target `Test1.o’ failed
    make: *** [Test1.o] Error 1.

    Any one known to solve this.

    • Here is my mak file declaration.

      ANDROID_NDK_BIN:=/cygdrive/e/android/standalone-14/bin
      #Compilation Tools

      CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc
      CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++
      AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar

      CFLAGS := -I../include

      # Rule for making C++ object file

      .cpp.o: $(CPP) $(CFLAGS) -c $<

      # Rule for making C object file

      .c.o: $(CC) $(CFLAGS) -c $<

      STATIC_LIB_SRC = Test1.cpp \
      Test2.cpp

      STATIC_LIB_OBJ = Test1.o \
      Test2.o

      OUT = ccStaticLib.a

      $(OUT): $(STATIC_LIB_OBJ) $(AR) -crs $(OUT) $(STATIC_LIB_OBJ)

    • tariqzubairy says:

      The compiler was unable to find the header file i.e. (Test1.h). Make sure you have the include directory in StaticLibraryTest folder and the header file (Test1.h) should be in include directory as in make file script include path is referenced as “CFLAGS := -I../include” or you specify your include path with respect to your folder hierarchy.

      Let me know if it worked for you or query your problem again.

  4. Hello ,

    Thanks for reply.
    Actuall issue was spacing in my .mak file.
    Finnaly i can able to build it.

  5. Hello,

    From your example and step now i am try to build .a file for this C++ code.
    Here is link https://github.com/Zintinio/HappyHTTP ,from there i have to build .a file from happyhttp.cpp and happyhttp.h.

    Now below is my mak file declaration.

    ANDROID_NDK_BIN:=/cygdrive/e/android/standalone-14/bin
    #INCLUDE := /cygdrive/d/Projects/CCode/StaticLibTest/include
    #Compilation Tools
    #D:\Projects\CCode\StaticLibTest

    CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc
    CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++
    AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar

    CFLAGS := -I../include
    # Rule for making C++ object file
    .cpp.o:
    $(CPP) $(CFLAGS) -c $<

    # Rule for making C object file
    .c.o:
    $(CC) $(CFLAGS) -c $<

    STATIC_LIB_SRC = happyhttp.cpp

    STATIC_LIB_OBJ = happyhttp.o

    OUT = happyhttp.a

    $(OUT): $(STATIC_LIB_OBJ)
    $(AR) -crs $(OUT) $(STATIC_LIB_OBJ)

    Now when i run make command it give below error.

    $ make -f make-static-library.mak
    /cygdrive/e/android/standalone-14/bin/arm-linux-androideabi-g++ -I../include -chappyhttp.cpp
    In file included from happyhttp.cpp:28:0:
    ../include/happyhttp.h:33:15: fatal error: map: No such file or directory
    compilation terminated.
    make-static-library.mak:13: recipe for target `happyhttp.o' failed
    make: *** [happyhttp.o] Error 1

    Any one known that how i can build .a file of happyhttp.cpp and happyhttp.h with out any issue.

    Thanks for any help.

  6. tttan jp says:

    a lot Thanks

    i develop on linux,
    so, i change

    $ make -f make-static-library.mak
    TO
    $ mv make -f make-static-library.mak makefile
    $ make

    Thanks ….

    • tttan jp says:

      Oh ! misstake …

      $ LANG=c make -n –f make-static-library.mak
      make: *** No rule to make target `–f’. Stop.
      $ make-static-library.mak makefile
      $ make

      OK ! fine

  7. Shinjo says:

    I have some Problems with this Tutorial !

    $ make -f make-static-library.mak
    make: *** Keine Regel vorhanden, um das Target »-crs«,
    benötigt von »ccStaticLib.a«, zu erstellen. Schluss.

    ANDROID_NDK_BIN:=/cygdrive/c/Users/sturmrt/Desktop/toolchain/bin

    # Compilation Tools

    CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc

    CPP:= $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++

    AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar

    # Compiler flags

    # Specify all the flags below which you want to use for your compilation, For this simple example, we only need to specify the include directory path

    CFLAGS:=-I /cygdrive/c/Users/sturmrt/Desktop/StaticLibraryTest/include

    # Rule for making C++ object file

    STATIC_LIB_SRC = Test1.cpp Test2.cpp

    STATIC_LIB_OBJ = Test1.o Test2.o

    OUT = ccStaticLib.a

    $(OUT): $(STATIC_LIB_OBJ) $(AR) -crs $(OUT)$(STATIC_LIB_OBJ)

    ———————————————————————————————————————

    CFLAGS := -I../include do not work!

    arm-linux-androideabi-ar will not work!

    Where is my Mistake.

    Pleas Help me.

    • Shinjo says:

      Solution! I found the Mistake 😀

      It is a Tab: $(OUT): $(STATIC_LIB_OBJ) $(AR) -crs $(OUT)$(STATIC_LIB_OBJ)

      Solution: $(OUT): $(STATIC_LIB_OBJ)
      $(AR) -crs $(OUT)$(STATIC_LIB_OBJ)

      Great!

  8. Pingback: can i use ios static lib in android | BlogoSfera

  9. rahul says:

    Hi,
    I am trying to compile source code for fluidsynth from the web site: https://bitbucket.org/kunstmusik/fluidsynth-android
    1. Created a project in eclipse
    2. created the /jni folder
    3. Copied the code to /jni folder

    After compiling with the command ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk the obj folders have the file libfluidsynth_andriod.a in the the armeabi and armeabi-v7a folders. These are probably static libraries. Can I use this static library? Am I doing this correctly? Do I need to follow your next article ‘Use of prebuild static Library compiled with Android Toolchain’ to add link from java to c/C++?

    Thanks for any help

  10. Peter Csanyi says:

    Hi,
    Very nice tutorial!
    I have some questions :
    1. what does extern means in line : “extern int test2(int x, int y, int z);”?
    2. if i have a complete project, i should rewrite every .h files like this? or i can use them without any modification?

    Kind regards,
    Peter

  11. Please make the code parts in monospace font. This can be done by using the code tag while editing in text mode. Doing this will make the article more readable and better understandable.

  12. SURAJ PANDEY says:

    Hello Guys,
    I am trying the example which is provided in this tutorial.
    But I am getting the following error..
    make-static-library.mak:13: *** missing separator. Stop.

    I have extracted my Standalone Toolchain in c:\ drive. And In that extracted folder binaries are inside the path C:\android-ndk-r9\toolchains.
    kindly explain me what are the changes I need to do in my .mak file.
    Below is the make file I am using
    I am a beginner so I am sorry for any silly question or mistake.
    Kindly respond as soon as possible.If you need any further clarification kindly let me know.
    thanks
    ************************************************************************************************************************
    # This variable contains the path of bin directory which contains all the gnu tools required for compilation
    # I have extracted the standalone toolchain for Android platform 14 in “e:\android\standalone-14”
    ANDROID_NDK_BIN:= c/android-ndk-r9/toolchains
    #/cygdrive/e/android/standalone-14/bin
    # Compilation Tools
    CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc
    CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++
    AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar
    # Compiler flags
    # Specify all the flags below which you want to use for your compilation, For this simple example, we only need to specify the include directory path
    CFLAGS := -I../include
    # Rule for making C++ object file
    .cpp.o: \
    $(CPP) $(CFLAGS) -c $<
    # Rule for making C object file
    .c.o:
    $(CC) $(CFLAGS) -c $<
    STATIC_LIB_SRC = Test1.cpp \
    Test2.cpp
    STATIC_LIB_OBJ = Test1.o \
    Test2.o
    OUT = ccStaticLib.a
    $(OUT): $(STATIC_LIB_OBJ)
    $(AR) -crs $(OUT) $(STATIC_LIB_OBJ)

    • SURAJ PANDEY says:

      Ok guy’s, I got solution.
      Tab was need at the particular line.

      now I have another issue as follow.
      *****************************************************************************************************
      C:\Users\Suraj\Desktop\Cygwin\StaticLibraryTest\src>make -f make-static-library.
      mak
      c:\android-ndk-r9\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\b
      in /arm-linux-androideabi-g++ -I../include -c Test1.cpp
      make: c:android-ndk-r9toolchainsarm-linux-androideabi-4.8prebuiltwindows-x86_64b
      in: Command not found
      make-static-library.mak:14: recipe for target ‘Test1.o’ failed
      make: *** [Test1.o] Error 127
      *************************************************************************************************************
      Path given in my make file is as follows.

      # This variable contains the path of bin directory which contains all the gnu tools required for compilation
      # I have extracted the standalone tool chain in c:\android-ndk-r9\toolchains
      ANDROID_NDK_BIN:=c:\android-ndk-r9\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin
      # Compilation Tools
      CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc
      CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++
      AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar
      # Compiler flags
      # Specify all the flags below which you want to use for your compilation, For this simple example, we only need to specify the include directory path
      CFLAGS:= -I../include
      # Rule for making C++ object file
      .cpp.o:
      $(CPP) $(CFLAGS) -c $<
      # Rule for making C object file
      .c.o:
      $(CC) $(CFLAGS) -c $<
      STATIC_LIB_SRC = Test1.cpp \
      Test2.cpp
      STATIC_LIB_OBJ = Test1.o \
      Test2.o
      OUT = ccStaticLib.a
      $(OUT): $(STATIC_LIB_OBJ)
      $(AR) -crs $(OUT) $(STATIC_LIB_OBJ)

  13. Michael Grieswald says:

    Just thought the whole Windows is going to fall into cygwin. #funny

  14. stefano says:

    Hi! thank you for this sample code.
    I’m on macOS and I”m getting the error: *** No rule to make target `-crs’, needed by `test.a’

    here is my mak:
    ANDROID_NDK_BIN:=android-toolchain/bin
    CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-clang
    CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++
    AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar
    CFLAGS := -I../include
    .c.o: $(CC) $(CFLAGS) -c $<
    STATIC_LIB_SRC = test.c
    STATIC_LIB_OBJ = test.o
    OUT = test.a
    $(OUT): $(STATIC_LIB_OBJ) $(AR) -crs $(OUT) $(STATIC_LIB_OBJ)

  15. Cher Perrell says:

    Wooww… It’s a lot… Let’s me give a try and checkout… May be I may review it differently than others as I come form different background and my thoughts wary as per that, but as you said no wrong way. Thanks for encouragingLikeLiked by 1 person

  16. Pingback: Cross compiling static C hello world for Android using arm-linux-gnueabi-gcc

Leave a comment