I am trying my hand at Android JNI.
So far I have just written the basic Hello World Android JNI App.
Now I was thinking if it would be possible to build a .so file seperately. Then use that library in my JNI Layer C Code.
So basically I want to build a libsample.so using command line gcc in windows. Then use this .so file in the JNI I write for my android app.
So far from my understanding I should be able to do this by editing the Android.mk file.
But what would those edits be ?
EDIT: Source code attached.
jnitest.cpp -
#include <jni.h>
#include "specialPrint.h"
extern "C" jstring Java_com_example_hwjni_MainActivity_helloFromJni(JNIEnv *env, jobject thiz) {
return env->NewStringUTF(SpecialPrint("This is external .so talking."));
}
specialPrint.h -
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
char* SpecialPrint(char* s);
#ifdef __cplusplus
}
#endif
specialPrint.c -
#include <stdio.h>
#include "specialPrint.h"
char* SpecialPrint(char* s) {
return s;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyPrebuiltLib
LOCAL_SRC_FILES = specialPrint.c
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := jnitest
LOCAL_SRC_FILES := jnitest.cpp
LOCAL_SHARED_LIBRARIES := MyPrebuiltLib
include $(BUILD_SHARED_LIBRARY)
P.S. - Although right now I am trying to do this with the source. But eventually I really need to do this stuff without the source of specialPrint. If you could help me achive that then it would be great!
Step 1: declare a prebuilt library as module
Step 2: refer the prebuilt module as local shared library
for example
include $(CLEAR_VARS)
LOCAL_MODULE := MyPrebuiltLib
LOCAL_SRC_FILES = path/to/libSuper.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := DroidJNILib
LOCAL_SRC_FILES := AwsomeCode.cpp
LOCAL_SHARED_LIBRARIES := MyPrebuiltLib
include $(BUILD_SHARED_LIBRARY)
If you have the source
include $(CLEAR_VARS)
LOCAL_MODULE := MyPrebuiltLib
LOCAL_SRC_FILES =mysource.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := DroidJNILib
LOCAL_SRC_FILES := AwsomeCode.cpp
LOCAL_SHARED_LIBRARIES := MyPrebuiltLib
include $(BUILD_SHARED_LIBRARY)
Related
I have found recently that linking prebuilt static libraries from the ndk-build is fundamentally different than from within the android source tree (mm). Why is this?
// main.cpp
#include <stdio.h>
#include "doubler.hpp"
int main()
{
printf("test a static lib \n");
// library function
doubler *p = new doubler();
delete p;
return 0;
}
Android mk:
LOCAL_PATH := $(call my-dir)
###################### static lib ##################
### prebuilt lib works in NDK but not Android src
#include $(CLEAR_VARS)
#LOCAL_MODULE := doubleIt_prebuilt
#LOCAL_SRC_FILES := $(LOCAL_PATH)/libDoubler.a
#LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
##LOCAL_SRC_FILES := libDoubler.a
#include $(PREBUILT_STATIC_LIBRARY)
###################### test app ##################
include $(CLEAR_VARS)
# binary name
LOCAL_MODULE:= testApp
# c++ file extension
LOCAL_CPP_EXTENSION := .cpp
# src files
LOCAL_SRC_FILES := main.cpp
# include dir
LOCAL_C_INCLUDES := $(LOCAL_PATH)
### this works in Android src, but not in NDK
LOCAL_LDLIBS := -L$(LOCAL_PATH) -lDoubler
### prebuilt lib works in NDK but not Android src
#LOCAL_STATIC_LIBRARIES := doubleIt_prebuilt
#what to build
include $(BUILD_EXECUTABLE)
Ultimately, what is the correct way to link a static lib in the src tree?
Why is this?
ndk-build and the AOSP build system are two entirely different build systems that unfortunately look very similar.
Ultimately, what is the correct way to link a static lib in the src tree?
In the AOSP tree? Prebuilt modules are defined differently. Here are a couple examples:
https://android.googlesource.com/platform/prebuilts/sdk/+/9c011b3a7784803b96dc0f0a840aa9033a0cd62a/tools/Android.mk#291
include $(CLEAR_VARS)
LOCAL_MODULE := libbcc
LOCAL_SRC_FILES := $(HOST_OS)/lib64/$(LOCAL_MODULE)$(HOST_SHLIB_SUFFIX)
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_SUFFIX := $(HOST_SHLIB_SUFFIX)
LOCAL_IS_HOST_MODULE := true
LOCAL_MULTILIB := 64
include $(BUILD_PREBUILT)
https://android.googlesource.com/platform/development/+/518e6c3a28cc63fd094c8b255e268650b03fdab5/host/windows/prebuilt/usb/Android.mk
include $(CLEAR_VARS)
LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE := AdbWinApi
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_SRC_FILES_x86 := AdbWinApi.a
LOCAL_MODULE_SUFFIX := .a
LOCAL_MULTILIB := 32
LOCAL_MODULE_HOST_OS := windows
include $(BUILD_PREBUILT)
You then use them the same way you would any other library: LOCAL_STATIC_LIBRARIES := libmyprebuilt. Both of the above examples are for host modules. For a target module simply remove that line.
Note that AOSP's new (still in progress) build system, Soong, does not yet have support for prebuilt modules. These can only be defined in Android.mk files right now.
I'm trying to link libmedia_jni.so in my android project so that I could access android_media_MediaCodec.h, but It fails to find the header.
my .cpp:
#include <jni.h>
#include <media/android_media_MediaCodec.h>
and Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := AndroidMediaCodec
LOCAL_SRC_FILES := AndroidMediaCodec.cpp
LOCAL_SHARED_LIBRARY := libmedia_jni
include $(BUILD_SHARED_LIBRARY)
I just want to link the library, because I don't have the whole framework. Is that even possible?
I need your help because it drives me crazy. What cause my error?
The error is
"jni/algorithm.cpp:4:33: fatal error: opencv2/core/core.hpp: No such file or directory #include <opencv2/core/core.hpp>
^ compilation terminated. make: *** [obj/local/arm64-v8a/objs/algorithm/algorithm.o] Error 1"
My algorithm.cpp is:
#include <jni.h>
#include <string.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
using namespace std;
using namespace cv;
extern "C"
{
JNIEXPORT jlong JNICALL Java_com_example_hematoma_MainActivity_fce(JNIEnv *env, jobject obj, jlong matimage)
{
Mat *jni_image = (Mat*) matimage;
return (jlong)jni_image;
}
}
My Android.mk is:
LOCAL_PATH := $(call my-dir)
include /home/nemesis/adt-bundle-linux-x86_64-20140702/OpenCV-2.4.10-android-sdk/sdk/native/jni/OpenCV.mk
include $(CLEAR_VARS)
LOCAL_MODULE := algorithm
LOCAL_SRC_FILES := algorithm.cpp
LOCAL_C_INCLUDE := /home/nemesis/adt-bundle-linux-x86_64-20140702/OpenCV-2.4.10-android-sdk/sdk/native/jni/include/opencv2/core/core.hpp
LOCAL_C_INCLUDE += /home/nemesis/adt-bundle-linux-x86_64-20140702/OpenCV-2.4.10-android-sdk/sdk/native/jni/include/
include $(BUILD_SHARED_LIBRARY)
The error occurs when ndk try to build .so
Thanks in advance.
LOCAL_C_INCLUDE := /home/nemesis/adt-bundle-linux-x86_64-20140702/OpenCV-2.4.10-android-sdk/sdk/native/jni/include/opencv2
should be
LOCAL_C_INCLUDES := /home/nemesis/adt-bundle-linux-x86_64-20140702/OpenCV-2.4.10-android-sdk/sdk/native/jni/include
ie, it is plural and should point to the location from which the following is a relative path:
#include <opencv2/core/core.hpp>
I solved my problem by add LOCAL_LDLIBS += -llog -ldl to "Android.mk"
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include C:/.../OpenCV-3.1.0-android-sdk/OpenCV-android-sdk/sdk/native/jni/OpenCV.mk
LOCAL_MODULE := Testappcv
LOCAL_SRC_FILES := Testappcv.cpp
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
And added "Application.mk" file to jni folder
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-8
So, I tried to change in Project properties C/C++ Build -> Build command from ${NDKROOT}/ndk-build to ${NDKROOT}/ndk-build.cmd and it solved all my include libs errors. weird
My source file can not include some header, because of local flag is not defined.
SSS.cpp:
#include <jni.h>
//This code is not defined:
#ifdef WORD
#include "Word.h"
#endif
//...rest of code
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := word
LOCAL_CPPFLAGS := -DWORD
LOCAL_SRC_FILES := SSS.cpp
include $(BUILD_SHARED_LIBRARY)
And one more moment, project build was successful, but I can not run it because of lots of errors in source file (Eclipse c++ editor still can not see my header).
Probably not -WORD but -DWORD ?
-D defines a macro to be used by the preprocessor.
And what this
-std=c++11
belongs to?
First.h
#ifndef FIRST_H
#define FIRST_H
class Test
{
public:
void create();
void test();
private:
};
#endif /* FIRST_H */
Second.cpp
#include "first.h"
#ifdef __cplusplus
extern "C" {
#endif
jint
Java_com_example_ndkcpp2_MainActivity_stringFromJNI( JNIEnv* env,
jobject thiz )
{
Test t;
t.test();
}
#ifdef __cplusplus
}
#endif
When I do a NDK-Build on second.cpp I got
pp2/jni/second.cpp:44: error: undefined reference to 'Test::test()'
collect2: ld returned 1 exit status
Using C++, you declare Class in .h file and write implementation in .cpp file. for example, you created First.h, then you should create First.cpp, in which write your method implementation like void Test::test(){}. Remember to add First.cpp to your makefile(Android.mk) for compilation.
You have multiple options here assuming that you have a first.cpp file that you implemented the Test class correctly. Without being able to see your Android.mk, I will go through all options:
Build First.cpp as a static or shared library and add this library to your module which compiles Second.cpp. Your Android.mk should look like:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := firstlib
LOCAL_C_INCLUDES := path/to/first.h
LOCAL_SRC_FILES := first.cpp
include $(BUILD_STATIC_LIBRARY)
If you would like First to be a shared library instead of a static library, change include $(BUILD_STATIC_LIBRARY) line to:
include $(BUILD_SHARED_LIBRARY)
Now, your second lib is compiled as follows:
include $(CLEAR_VARS)
LOCAL_MODULE := second
LOCAL_C_INCLUDES := path/to/first.h
LOCAL_C_INCLUDES += path/to/second.h
LOCAL_SRC_FILES := second.cpp
LOCAL_STATIC_LIBRARIES := firstlib
include $(BUILD_SHARED_LIBRARY)
If firstlib is built as shared library, you can link it by chaning LOCAL_STATIC_LIBRARIES += firstlib line to the following:
LOCAL_SHARED_LIBRARIES += firstlib
As a second solution, you can build first.cpp as a part of the second lib and this way you don't have to worry about linking against the first library. This is more like a design choice and how you would like to shape up your libraries:
include $(CLEAR_VARS
LOCAL_MODULE := libtwolib-second
include $(CLEAR_VARS)
LOCAL_MODULE := libtwolib-second
LOCAL_C_INCLUDES := path/to/first.h
LOCAL_C_INCLUDES += path/to/second.h
LOCAL_SRC_FILES := first.cpp
LOCAL_SRC_FILES += second.cpp
include $(BUILD_SHARED_LIBRARY)
Finally, you can find a sample of the first approach in your NDK directory, under samples/twolibs.