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.
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
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
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.
Hello,
Cool and clear tuturail, builded from first atemp.
Thanks
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)
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.
Hello ,
Thanks for reply.
Actuall issue was spacing in my .mak file.
Finnaly i can able to build it.
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.
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 ….
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
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.
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!
Pingback: can i use ios static lib in android | BlogoSfera
You can’t use the ios static library in Android because the underlying architecture are different for both platforms
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
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
Oh and one more question :
can i build c++ project with CXXFLAGS=”–stdlib=libstdc++” for android?
Yes you can use CXXFLAGS for Android compilation. I recommend you to go through the NDK documentation
For first question i recommend you to follow the link given below
http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/
Secondly, I don’t think that you need any modification in your header files. I write this blog with the simplest example and compiled many open source project using the same technique without modifying the actual project.
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.
Thanks for valuable suggestion. The blog is updated as per your suggestion.
Looks great.
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)
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)
Just thought the whole Windows is going to fall into cygwin. #funny
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)
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
Pingback: Cross compiling static C hello world for Android using arm-linux-gnueabi-gcc