I need to generate ARM structure shared library for a sampleCPP project.
Sample projects contains:
CMakeLists.txt
some.cpp (s)
Some.h (s)
some.tab.cpp.make (S)
some.tab.hpp.cmake (s)
Now, I want to create a shared library for a different Android project. I tried to compile with [Android-Cmake][1]but it is generating X86 Architecture library not ARM.
Please let me know if there is another way to do it. Also can i run X86 on Android Platform for all version?
Edit :
Here is my Android.mk:
LOCAL_PATH := $(call my-dir)/../ //Path is according JNI Folder
SRC_TOP_DIR := $(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE := smileParse
LOCAL_CFLAGS := -DANDROID
LOCAL_SRC_FILES := main.cpp test.cpp smamain.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include $(LOCAL_PATH)/
Create a folder called JNI in your project:
Create or Edit Android.mk in JNI folder, set include and library path,
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := some.cpp
include $(BUILD_SHARED_LIBRARY)
Declare a java wrapper class, declare a native function:
public class JWrapperSomeClass {
public native void Demo(int para);
}
use javah command to generate the function signature for your C++ method wrapper:
javah -jni -classpath bin/classes/ -d jni com.example.Your.Package.Class
Edit the code in C++
Go to your project folder, run command:
$ANDROID_NDK/ndk-build
where $ANDROID_NDK is the folder where you installed android NDK
That is pretty much it. For more details, you might read NDK or JNI documentation.
Related
I've downloaded OpenCV for Android Version 3.2 and imported its java module to my project. I've copied the native (c++) codes into modules directory in openCVLibrary320/app/src/main/jni.
How can I create Application.mk and Android.mk for compiling this sdk? (As i know that ndk-build need these two files)
Its easy follow my all point you will do it ,
import your Opencv ( as u did already)
now goto your project Structure select app than Add new Dependencies and select your opencv Module click ok
Crete a class call it NativeClass.java it will contain your native function and variables
creat a method getMessage from JNI in your nativeClass.java and build that
Now Open Terminal and wirte this
1) cd app/src/main
2) javah -d jni -classpath ../../build/intermediates/classes/debug write_your_Pakage_Name.className
My pakage name is com.example.cvlab.ndktest
class name -->nativeClass
when u write above code in terminal click enter it will create jni folder and it will have header file
Now copy headerfile and past it in same folder but write .cpp instead of .h
copy function jni function from header file and past that in your cpp file
build that if shows error goto gradle file and write
android.usedeprecatedndk=true
Now create android.mk file in your jni folder and add this code
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#opencv
OPENCVROOT:= your opencv location
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include ${OPENCVROOT}/sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := your cpp file name
LOCAL_LDLIBS += -llog
LOCAL_MODULE := MyLibs
include $(BUILD_SHARED_LIBRARY)
now create Application.mk file and write this code
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-16
now go to your build.gradel file and afther defultConfiguation put this
sourceSets.main {
jni.srcDirs = [] //disable automatic ndk-build call
}
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
commandLine "C:/Users/do/AppData/Local/Android/sdk/ndk-bundle /ndk-build.cmd",
'NDK_PROJECT_PATH=build/intermediates/ndk',
'NDK_LIBS_OUT=src/main/jniLibs',
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
'NDK_APPLICATION_MK=src/main/jni/Application.mk'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
Note: if you installed your android stdk and ndk than you have to give that folder location in commond line like this C:/Users/do/AppData/Local/Android/sdk/ndk-bundle
now build that it will create jnilibs fodler and it will contains your libs files
now goto your mainjava file and load this
static {
System.loadLibrary("MyLibs");
}
to call your native code write NativeClass.getMessageFromJNI()
and show that in Text view
If you want to use Java API for OpenCV, then you may have a look at this post.
However, if you want to use pre-built OpenCV static libs with C/C++ code on NDK side then only you will require Android.mk and Application.mk. In my version of these .mk files, I dynamically load the required pre-built libraries from a location on my drive, So while building, .mk files will load the required static libs.
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Location of SDK on my drive
OPENCVROOT := ${HOME}/opencv-sdk-android
OPENCV_CAMERA_MODULES := off
OPENCV_INSTALL_MODULES := on
OPENCV_LIB_TYPE := STATIC
include ${OPENCVROOT}/sdk/native/jni/OpenCV.mk
# Load your local .cpp and .h files here.
LOCAL_SRC_FILES := hello-jni.c
LOCAL_LDLIBS := -lm -llog -ldl -lz
LOCAL_CPPFLAGS += -fexceptions -frtti -std=c++11
LOCAL_LDFLAGS += -ljnigraphics
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL := gnustl_static
APP_CPPFLAGS += -fexceptions -frtti -std=c++11 -D__STDC_CONSTANT_MACROS
APP_ABI := all
APP_PLATFORM=android-14
Although you've requested Android.mk for ndk-build, I would like to suggest CMake which Android Developers recommends for use with native projects.
In that case, you could check out my answer which provides two solutions to integrate the OpenCV 3.2.0 SDK into the Android Project/Application. The implementation provides proper and tested integration, and it leverages the CMakeLists.txt scripts found within the OpenCV SDK to build and link the library modules (included 3rd Party and SDK libs) properly, and it also includes the header files to code in native C/C++ classes which are part of the project.
I wanted to create a Prebuilt Shared library .so from .c file for ARM processor. Kindly give me some steps to do this and also how to include and access its functions in android.
You are looking for:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_static_lib
LOCAL_C_INCLUDES := src
LOCAL_SRC_FILES := src/main_main.c
# Use this one to build a *.a file - static library
include $(BUILD_STATIC_LIBRARY)
# Use this one to build a *.so file - a shared library
include $(BUILD_SHARED_LIBRARY)
I am using native code in my android app. Firstly I was only using one library. So everything worked fine. But now I have to integrate one more library into it. I've no idea what should be the ideal structure of the jni folder of my project (as in where to place the entire code, etc.). I found a work around. I created two folders inside jni .i.e library1 and library2. Again created a jni folder inside both the folders and placed respective code in the folders.
I got it to compile. Both .so files are being generated, but I am unable to use it in my application. I cant load the library using System.loadLibrary("library1.so"); Also tried providing full path. But failed
Also I have no idea what to write inside the parent jni folder's Android.mk file.
Current structure:
project_folder -> jni -> library1 -> jni -> "source code" an Android.mk is written here
project_folder -> jni -> library2 -> jni -> "source code" an Android.mk is written here
UPDATE #1 :
Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
make: *** No rule to make target `jni/zap/jni/zap/zap/error.c', needed by `obj/local/armeabi/objs-debug/zap/jni/zap/zap/error.o'. Stop.
I am not using Application.mk.
This is my Android.mk:
TOP_PATH := $(call my-dir)
# Build library 1
include $(CLEAR_VARS)
LOCAL_PATH := $(TOP_PATH)/zap
LOCAL_MODULE := zap
LOCAL_C_INCLUDES := $(LOCAL_PATH)/zap
LOCAL_SRC_FILES := $(LOCAL_PATH)/zap/error.c \
$(LOCAL_PATH)/zap/hello-jni.c \
$(LOCAL_PATH)/zap/zap.c \
$(LOCAL_PATH)/zap/zapd.c \
$(LOCAL_PATH)/zap/zaplib.c
include $(BUILD_SHARED_LIBRARY)
The best structure I've found is to use the jni/ folder for ndk-build makefiles only, and keep the source outside in their own folders. This is easy to add to existing projects without restructuring your tree under jni.
However, you do have to be careful about how you handle the LOCAL_PATH variable and use of $(call my-dir). Here's a working example:
MyProject/
library1/
source1.cpp
library2/
source2.cpp
jni/
Android.mk
Application.mk
Android.mk:
# TOP_PATH refers to the project root dir (MyProject)
TOP_PATH := $(call my-dir)/..
# Build library 1
include $(CLEAR_VARS)
LOCAL_PATH := $(TOP_PATH)/library1
LOCAL_MODULE := library1
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := source1.cpp
include $(BUILD_SHARED_LIBRARY)
# Build library 2
include $(CLEAR_VARS)
LOCAL_PATH := $(TOP_PATH)/library2
LOCAL_MODULE := library2
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := source2.cpp
include $(BUILD_SHARED_LIBRARY)
You can optionally split out the sections in Android.mk to their own makefiles.
I discovered that when compiling from the command line, I can include multiple libraries by running android update project twice, once with each library:
android update project -l ../SDK/library1/ --path . --name $name --target 23 --subprojects
android update project -l ../SDK/library2/ --path . --name $name --target 23 --subprojects
ant release
Here I used this Android.mk file in jni/ folder.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and source file(s)
LOCAL_MODULE := offlineDownload
LOCAL_SRC_FILES := offline_download.c
LOCAL_SHARED_LIBRARIES :=../lib/libpackext.so.1.0
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
And make one lib folder in project directory and put my prebuilt .so library and make one Android.mk file which contains following
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := packext
LOCAL_SRC_FILES := libpackext.so.1.0
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
include $(PREBUILT_SHARED_LIBRARY)
And when i use ndk-build -B command than i got undefined reference to packageExtraction. Here I use my prebuilt library functions means I can't link my prebuilt shared library to my offlinedownload library.
So any body please help me to solved out this issue.
Here is a complete Android.mk file for using a 3rd party shared library.
The library (libffmpeg.so) is placed in the jni folder.
Its "LOCAL_EXPORT_C_INCLUDES" specifies where the header files are kept for the library.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := libffmpeg.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../ffmpeg/libs/arm-linux-androideabi4.7_1/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpegandroid
LOCAL_SRC_FILES := ffmpegandroid.c
LOCAL_SHARED_LIBRARIES := ffmpeg
include $(BUILD_SHARED_LIBRARY)
If you wanted to support multiple architectures then you could specify:
APP_ABI := armeabi armeabi-v7a x86 mips
in your jni/Application.mk and change the LOCAL_SRC_FILES to something like:
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libffmpeg.so
and place a libffmpeg.so at jni/armeabi/libffmpeg.so, jni/armeabi-v7a/libffmpeg.so etc ..
Android NDK official hello-libs CMake example
https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs
Just worked for me on Ubuntu 17.10 host, Android Studio 3, Android SDK 26, NDK 15.2. so I strongly recommend that you base your project on it.
The shared library is called libgperf, the key code parts are:
hello-libs/app/src/main/cpp/CMakeLists.txt:
// -L
add_library(lib_gperf SHARED IMPORTED)
set_target_properties(lib_gperf PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/gperf/lib/${ANDROID_ABI}/libgperf.so)
// -I
target_include_directories(hello-libs PRIVATE
${distribution_DIR}/gperf/include)
// -lgperf
target_link_libraries(hello-libs
lib_gperf)
on C++ code, use: #include <gperf.h>
header location: hello-libs/distribution/gperf/include/gperf.h
lib location: distribution/gperf/lib/arm64-v8a/libgperf.so
app/build.gradle:
android {
sourceSets {
main {
// let gradle pack the shared library into apk
jniLibs.srcDirs = ['../distribution/gperf/lib']
Then, if you look under /data/app on the device, libgperf.so will be there as well.
If you only support some architectures, see: Gradle Build NDK target only ARM
The example git tracks the prebuilt shared libraries, but it also contains the build system to actually build them as well: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs
You have to do either one of the following:
Cut and paste everything except LOCAL_PATH := $(call my-dir) from your second Android.mk into your first.
Put the following in the end of your first Android.mk:
$(call import-module,packext)
Also make sure that you set your NDK_MODULE_PATH environment variable to a path where the Android.mk-file defining the module packext can be found.
You also have to change the LOCAL_SHARED_LIBRARIES in the same way mgiza said in the first answer. I suppose the packageExtraction that you got undefined reference to is in your prebuilt library so unless you have other linking problems this should solve the issue.
Have a look at the ndk documentation for prebuilts:
android-ndk/docs/PREBUILTS.html
You have to change
LOCAL_SHARED_LIBRARIES :=../lib/libpackext.so.1.0
to
LOCAL_SHARED_LIBRARIES := packext
Be sure that your folder containing the Android.mk for the packext module is named packext and can be found in in your NDK_MODULE_PATH.
I'm trying to compile a static library to use on Android but I can't figure out how to compile it. The library uses standard libraries (stdio.h etc...) and libxml2.
I am trying to compile using arm-eabi-gcc but I get the following error:
/cygdrive/c/android-ndk-r4/build/platforms/android-8/arch-x86/usr/include/asm/posix_types.h:15:28: error: posix_types_64.h: No such file or directory
How do I get this to work?
As I understand it, the correct method is to use ndk-build and not invoking the compiler directly.
In Android.mk you need to specify a module for each static library you want to compile, and then specify that your shared library should use it.
Example of a modified Android.mk file of the hello-jni sample project:
LOCAL_PATH := $(call my-dir)
# Define vars for library that will be build statically.
include $(CLEAR_VARS)
LOCAL_MODULE := <module_name>
LOCAL_C_INCLUDES := <header_files_path>
LOCAL_SRC_FILES := <list_of_src_files>
# Optional compiler flags.
LOCAL_LDLIBS = -lz -lm
LOCAL_CFLAGS = -Wall -pedantic -std=c99 -g
include $(BUILD_STATIC_LIBRARY)
# First lib, which will be built statically.
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_STATIC_LIBRARIES := <module_name>
LOCAL_C_INCLUDES := <header_files_path>
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
If you want control over which modules to compile when you run ndk-build you can create create a Application.mk file (in the same directory as Android.mk) and list all the modules as in the following example:
APP_MODULES := <module_name_1> <module_name_2> ... <module_name_n>
In response to
Can you generate a static library (.a file) without a shared library
that uses it?
(which really should have been its own question), the answer is yes.
By default, the NDK will only build executables and shared libraries (with their dependencies of course). You can, however, force the NDK to build a standalone static library by explicitly referencing it in your Application.mk.
Assuming your static library module is LOCAL_MODULE := libXYZ, add the following line to Application.mk (creating the file in the same folder as your Android.mk if it doesn't exist):
APP_MODULES := XYZ
Note the the APP_MODULES value does not include the lib prefix included in your static library module name.
Alternatively, if you don't want to create an Application.mk, you can specify the value on the command line: ndk-build APP_MODULES=XYZ
A cool trick: if you have an Android.mk file, you can change the build type from:
include $(BUILD_SHARED_LIBRARY)
to
include $(BUILD_STATIC_LIBRARY)
and .a libraries will be output to the obj/ folder into their respective architectures when you ndk-build the library.