in JNI folder:
//File foo.h
#ifndef FOO_H_
#define FOO_H_
class Foo {
public:
Foo();
void Funny();
};
#endif /* FOO_H_ */
//File foo.cpp
#include "foo.h"
cv::string bar[1] = {"FOO"};
Foo::Foo() {
}
void Foo::Funny() {
}
Then, when I call:
Foo foo;
foo.Funny();
ndk-build complains:
error: undefined reference to 'Foo::Foo()
error: undefined reference to 'Foo::Funny()
However, if I put the function implementation in the header file like this:
#ifndef FOO_H_
#define FOO_H_
class Foo {
public:
Foo();
void Funny();
};
Foo::Foo() {
}
void Foo::Funny() {
}
#endif /* FOO_H_ */
The compiler then happily compiles my code.
How could I separate function prototypes and their implementation in JNI?
UPDATE: Here's my Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_LIB_TYPE:=STATIC
OPENCV_INSTALL_MODULES:=on
include ../../sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := native.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog -ldl
LOCAL_MODULE := native
include $(BUILD_SHARED_LIBRARY)
The undefined reference is outputted by the linker, not by the Compiler. This means there is no translation unit containing the functions you have used in your code. Telling by the Android.mk file I'd say foo.cpp is missing in your LOCAL_SRC_FILES Statement.
Related
In Android, I am facing issues in connecting two cpp class in native Android. I have tested with the single class it working fine.
but when I have created another file and now facing an issue in linking it with current cpp file.
MainClass.cpp
#include <jni.h>
#include "native-handler.h"
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_fragment_SampleFragment_setTitle(JNIEnv *env,jobject instance,jobject context) {
ClassNativeHandler classNativeHandler;
return classNativeHandler.getType(env,context);
}
native-handler.cpp
#include <jni.h>
#include "native-handler.h"
jstring jstringObject;
jstring ClassNativeHandler::getType(JNIEnv *env, jobject contextObject) {
jstring jstringObject = env->NewStringUTF("Hello world");
return jstringObject;
}
void ClassNativeHandler::setType(jstring string) {
myType = string;
jstringObject = string;
}
native-handler.h
#ifndef SAMPLE_NATIVE_HANDLER_H
#define SAMPLE_NATIVE_HANDLER_H
#include <iostream>
#include <string>
class ClassNativeHandler
{
private:
jstring myType;
public:
void setType(jstring string);
jstring getType(JNIEnv *env, jobject contextObject);
jstring getHeaderName(JNIEnv *env);
};
#endif //SAMPLE_NATIVE_HANDLER_H
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Native
LOCAL_SRC_FILES := ../cpp/mainClass.cpp
LOCAL_C_INCLUDES := ../cpp/native-handler.h
LOCAL_LDLIBS := -lz -llog -ljnigraphics
include $(BUILD_SHARED_LIBRARY)
Error : undefined reference to `ClassNativeHandler::getType(_JNIEnv*, _jobject*)'
on this line
return classNativeHandler.getType(env,context);
So I am not able to build the .so file. Please guide me
You haven't compiled native-handler.cpp. You need to specify it in LOCAL_SRC_FILES so that NDK compiles it.
LOCAL_SRC_FILES := ../cpp/mainClass.cpp ../cpp/native-handler.cpp
I have made a project with OpenCV and i need to use Native Code for realtime processing purpose, following the guide on this book opencv3, here is my Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := FinalCamJNI
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_LDLIBS := -lstdc++ # C++ standard library
LOCAL_LDLIBS += -llog # Android logging
LOCAL_LDLIBS += -lz # zlib
LOCAL_STATIC_LIBRARIES := opencv_calib3d
LOCAL_STATIC_LIBRARIES += opencv_features2d
LOCAL_STATIC_LIBRARIES += opencv_flann
LOCAL_STATIC_LIBRARIES += opencv_imgproc
LOCAL_STATIC_LIBRARIES += opencv_core
LOCAL_SRC_FILES := FinalCamJNI.cpp RecolorRCFilter.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := opencv_calib3d
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libopencv_calib3d.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := opencv_features2d
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libopencv_features2d.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := opencv_flann
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libopencv_flann.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := opencv_imgproc
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libopencv_imgproc.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := opencv_core
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libopencv_core.a
include $(PREBUILT_STATIC_LIBRARY)
and here is my Application.mk file:
APP_STL := gnustl_static # GNU STL
APP_CPPFLAGS := -frtti –fexceptions # RTTI, exceptions
APP_ABI := armeabi armeabi-v7a mips x86
APP_PLATFORM := android-8
I'm facing this error when performing ndk-build:
I have checked the directory, and ensured that i have prepared all the code file
in jni folder.
In addition, here is my implementation file:
FinalCamJNI.cpp:
#include <jni.h>
#include "RecolorRCFilter.hpp"
using namespace finalcam;
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jlong JNICALL
Java_nahuy_hcmus_finalcam_filters_newSelf(
JNIEnv *env, jclass clazz)
{
RecolorRCFilter *self = new RecolorRCFilter();
return (jlong)self;
}
JNIEXPORT void JNICALL
Java_nahuy_hcmus_finalcam_filters_deleteSelf(
JNIEnv *env, jclass clazz, jlong selfAddr)
{
if (selfAddr != 0)
{
RecolorRCFilter *self = (RecolorRCFilter *)selfAddr;
delete self;
}
}
JNIEXPORT void JNICALL
Java_nahuy_hcmus_finalcam_filters_apply(
JNIEnv *env, jclass clazz, jlong selfAddr, jlong srcAddr,jlong dstAddr)
{
if (selfAddr != 0)
{
RecolorRCFilter *self = (RecolorRCFilter *)selfAddr;
cv::Mat &src = *(cv::Mat *)srcAddr;
cv::Mat &dst = *(cv::Mat *)dstAddr;
self->apply(src, dst);
}
}
#ifdef __cplusplus
} // extern "C"
#endif
RecolorRCFilter.hpp:
#ifndef RECOLOR_RC_FILTER
#define RECOLOR_RC_FILTER
#include <opencv2/core/core.hpp>
namespace finalcam {
class RecolorRCFilter
{
public: // All subsequent methods or variables are public.
void apply(cv::Mat &src, cv::Mat &dst);
private: // All subsequent methods or variables are private.
cv::Mat mChannels[4];
};
} // namespace secondsight
#endif // RECOLOR_RC_FILTER
RecolorRCFilter.cpp:
#include "RecolorRCFilter.hpp"
using namespace finalcam;
void RecolorRCFilter::apply(cv::Mat &src, cv::Mat &dst)
{
cv::split(src, mChannels);
cv::Mat g = mChannels[1];
cv::Mat b = mChannels[2];
// dst.g = 0.5 * src.g + 0.5 * src.b
cv::addWeighted(g, 0.5, b, 0.5, 0.0, g);
// dst.b = dst.g
g.copyTo(b);
cv::merge(mChannels, 4, dst);
}
Can anyone explain me why this happens and what I can do to solve this problem?
I want to use dynamic registration in native method, so I need set JNI_onLoad function. I just write a function to get sum of two numbers. But, it can't build correctly. How can I correct the error?
This is my *.cpp file, I name this file jni.cpp
#include <jni.h>
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
jni::jclass& nativeClass = jni::FindClass(env, "com/test/NativeClass");
#define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod<decltype(name), name>( #name, sig )
jni::RegisterNatives(env, nativeClass, MAKE_NATIVE_METHOD(nativeAddTest, "(II)I") );
return JNI_VERSION_1_6;
}
jlong nativeAddTest(JNIEnv *env, jni::jobject* obj, jni::jint a, jni::jint b) {
return a+b;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := jni.cpp
LOCAL_LDLIBS := -L/ndk-path/sources/cxx-stl/stlport/libs/armeabi
include $(BUILD_SHARED_LIBRARY)
When I use ndk-build command, it's wrong. But I really dont't konw the reason...
D:\WorkSpaces\Test\app\src\main\jni>ndk-build
[x86] Compile++ : test <= jni.cpp
D:/WorkSpaces/Test/app/src/main/jni/jni.cpp: In function 'jint JNI_OnLoad(JavaVM*, void*)':
D:/WorkSpaces/Test/app/src/main/jni/jni.cpp:9:5: error: 'jni' has not been declared
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
^
D:/WorkSpaces/Test/app/src/main/jni/jni.cpp:9:18: error: 'env' was not declared in this scope
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
....
It seems can't find jni.h, but I already have #include<jni.h>
In Android NDK, <jni.h> does not define a jni namespace. Simply remove all jni::
#include <jni.h>
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv env;
vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
jclass nativeClass = env->FindClass("com/test/NativeClass");
… and so on.
Add header location to your android.mk
LOCAL_C_INCLUDES := "path to your header location"
While compiling a CPP project into an .so library it generates the following errors :
...
jni/core/src/sqlite3/sqlite3c++.h:26: error: undefined reference to 'sqlite3cpp::database::mp_checkSqliteError(int, std::string)'
jni/core/src/sqlite3/sqlite3c++.h:51: error: undefined reference to 'sqlite3cpp::query::compile()'
jni/core/src/sqlite3/sqlite3c++.h:51: error: undefined reference to 'sqlite3cpp::database::mp_checkSqliteError(int, std::string)'
jni/core/src/sqlite3/sqlite3c++.h:53: error: undefined reference to 'sqlite3cpp::query::compile()'
...
Where those files are :
part of sqlite3c++.h :
.....
#include "sqlite3.h"
#ifndef MFDEPSAPI
#define MFDEPSAPI
#endif
namespace sqlite3cpp
{
class MFDEPSAPI database
{
public:
database(std::string databaseFile): mp_transactionInProgress(false), mp_SQLITE_db(0) { if(databaseFile.empty()) return; mp_checkSqliteError(sqlite3_open_v2(databaseFile.c_str(), &mp_SQLITE_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, 0), "opening database"); }
~database();
....
class MFDEPSAPI query
{
public:
query(database& db, const char* strQuery);
~query();
void compile();
....
}
}
part of sqlite3c++.cpp :
#include "sqlite3.h"
#include "sqlite3c++.h"
#include <iostream>
using namespace std;
namespace sqlite3cpp
{
....
int database::mp_checkSqliteError(int retVal, const std::string description)
{
switch(retVal)
{
case -1:
cerr << "non-typed sqlite library error: " << description << "\n";
return retVal;
break;
case SQLITE_ERROR:
case SQLITE_MISUSE:
case SQLITE_FULL:
case SQLITE_NOMEM:
case SQLITE_INTERRUPT:
case SQLITE_INTERNAL:
case SQLITE_PERM:
case SQLITE_CORRUPT:
case SQLITE_CANTOPEN:
case SQLITE_AUTH:
case SQLITE_RANGE:
case SQLITE_NOTADB:
cerr << "sqlite error: (" << retVal << ") " << sqlite3_errmsg(mp_SQLITE_db) << ", description: \"" << description << "\"" << "\n";
return retVal;
break;
default:
return retVal;
};
}
.....
query::query( database& db, const char* strQuery ) : mp_db(db), mp_isValid(false), mp_strQuery(strQuery), mp_currentIndex(0), mp_SQLITE_statement(0)
{
}
}
It's building with cygwin via nkd-build.cmd for android with this Android.mk:
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
#### sqlite3
# Here we give our module name and source file(s)
LOCAL_C_INCLUDES := core/src/sqlite3
LOCAL_MODULE := sqlite3
LOCAL_SRC_FILES := core/src/sqlite3/sqlite3.c
include $(BUILD_STATIC_LIBRARY)
#include $(BUILD_SHARED_LIBRARY)
#### Project
include $(CLEAR_VARS)
LOCAL_MODULE := libgame
LOCAL_CFLAGS := -Wall -Wextra
LOCAL_LDLIBS := -llog -lGLESv2
LOCAL_CPP_FEATURES += exceptions
LOCAL_STATIC_LIBRARIES := libsqlite3
LOCAL_SHARED_LIBRARIES := liblog libGLESv2
# To build the whole .so
FILE_LIST := $(wildcard $(LOCAL_PATH)/core/src/*.cpp)
LOCAL_SRC_FILES += $(FILE_LIST:$(LOCAL_PATH)/%=%)
INCLUDE_LIST := $(wildcard $(LOCAL_PATH)/core/src/*.h)
LOCAL_C_INCLUDES += $(INCLUDE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
It's probably just something I missed or got wrong configured.
Feel free to ask if more files or something is needed.
I am creating a constructor of class Level as follows but b I am getting an error message that:
D:\downloads\cocos2d-2.0-x-2.0.4\cocos2d-2.0-x-2.0.4\armadillo\proj.android/jni/../../Classes/HelloWorldScene.cpp:43: undefined reference to `Levels::Levels()'
D:\downloads\cocos2d-2.0-x-2.0.4\cocos2d-2.0-x-2.0.4\armadillo\proj.android/jni/../../Classes/HelloWorldScene.cpp:44: undefined reference to `Levels::getCachedDataFromFile(std::string)'
Code:
bool HelloWorld::init()
{
if ( !CCLayer::init() )
{
return false;
}
_levels = new Levels();
_levels->getCachedDataFromFile("\mnt\sdcard\levels.json");
return true;
}
I am calling this method in constructor in HelloWorld.cpp file. I have included Levels.h file in HelloWorld.h which I included in HelloWorld.cpp.
I'll be grateful if any one can help me out as I am beginner to cpp.
I have included the method and constructor in header file, you can check it in following code:
#include "Box2d.h"
#include "cocos2d.h"
using namespace cocos2d;
#ifndef LEVELS_H_
#define LEVELS_H_
class Levels: public b2ContactListener {
public:
Levels();
~Levels();
void BeginContact(b2Contact *contact);
void EndContact(b2Contact *contact);
void preSolve(b2Contact* contact, const b2Manifold* oldManifold);
void postSolve(b2Contact* contact, const b2ContactImpulse* impulse);
void getCachedDataFromFile(string filePath);
private:
// const string LEVEL_FILE_NAME = "levels.json";
};
#endif /* LEVELS_H_ */
Level.cpp
#include "Levels.h"
#include <android/log.h>
#define LOG_TAG "levels"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
Levels::Levels() {
}
Levels::~Levels() {
}
void Levels::BeginContact(b2Contact *contact) {
}
void Levels::EndContact(b2Contact *contact) {
}
void Levels::getCachedDataFromFile(string filePath) {
unsigned long filesize = 0;
unsigned char* fileData = NULL;
std::string content, fullPath;
int i =1;
fullPath = CCFileUtils::sharedFileUtils()- > fullPathFromRelativePath(filePath.c_str());
fileData = CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str(),
"r", &filesize);
content.append((char*) fileData);
LOGD(content.c_str());
// if (languagesDocument.Parse < 0 > (content.c_str()).HasParseError()) {
// LOGD(languagesDocument.GetParseError());
//// CCLog(languagesDocument.GetParseError());
// }
// return NULL;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
include ../../../projects/android-opencv/sdk/native/jni/OpenCV.mk
LOCAL_MODULE := game_shared
LOCAL_MODULE_FILENAME := libgame
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp
#Required for android log from jni code
LOCAL_LDLIBS += -llog -ldl
#Add path to OpenCV's header files
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
$(LOCAL_PATH)/../../libs/Box2d \
../../../projects/android-opencv/sdk/native/jni/include/
LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocosdenshion_static c cocos_extension_static box2d_static
include $(BUILD_SHARED_LIBRARY)
$(call import-module,CocosDenshion/android) \
$(call import-module,cocos2dx) \
$(call import-module,extensions) \
$(call import-module,Box2D)
Did you implement the constructor? In Levels.cpp add this:
Levels::Levels()
{
// constructor code here …
}
Likewise with the destructor:
Levels::~Levels()
{
// destructor code here …
}
You forgot to add Levels.cpp to the list of src files in your Android.mk. It should be:
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp \
../../Classes/Levels.cpp
Any file with classes that you create later should be added to the list as well.