I am doing development in Android using C/C++. I have a C++ function, that needs to be called from a C file. Here is what I am doing right now, but I get the error
undefined reference to __check_expiry
The C++ function is defined in "a.h" and implemented in "a.cpp". I am including "a.h" in"b.c" file and calling the method "__check_expiry" from "b.c" file.
a.h :
#ifdef __cplusplus
extern "C" {
#endif
static int __check_expiry(void);
#ifdef __cplusplus
}
#endif
a.cpp:
extern "C" {
static int __check_expiry() {
vz::lock_guard<std::mutex> guard(mutex_check, lock_hooker_check);
JNIEnv *env = NULL;
static bool __is_attached_1 = false;
if ((env = __getEnv(&__is_attached_1)) == NULL) {
//log_info("getEnv fail\r\n");
}
assert(!__is_attached_1);
int obj = env->CallStaticIntMethod((jclass) g_class, g_methodID);
log_info("Returned value from JAVA %d", obj);
__releaseEnv(__is_attached_1);
guard.~lock_guard();
return obj;
}
}
b.c:
#ifdef __cplusplus
extern "C" {
#endif
#include "a.h"
#ifdef __cplusplus
}
#endif
static int tunnel_to()
{
int value = __check_expiry();
}
Static functions are not exported. Remove the static qualifier.
(Unrelated: as long as you #include "a.h" from a.cpp, you don't need the extern "C" in your source file.)
Related
I have an Android Kotlin application that calls a simple JNI function, the latter calling a C++ singleton.
There is a crash (SIGABRT) when I call the JNI function. I can't see what is wrong...
Kotlin code :
stopProcessing() // Calls stopProcessing JNI function
JNI code :
extern "C"
JNIEXPORT void JNICALL
Java_com_tb_of_1ir_MainActivity_stopProcessing(JNIEnv *env, jobject thiz) {
static auto a = MySingleton::get();
a->stopProcessing();
}
C++ code :
[[noreturn]] void stopProcessing() {
}
There is nothing in the C++ code for now, but even if something inside (anything) there is the same problem.
Thanks !
Edit :
The singleton code :
#include "MySingleton.h"
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <signal.h>
#include <chrono>
#include <thread>
#include <bitset>
class MySingleton {
private:
static MySingleton *singleton;
explicit MySingleton() {
src_string = "The default string value";
}
public:
static MySingleton *get() {
if (singleton == nullptr)
singleton = new MySingleton();
return singleton;
}
bool MySingletonStarted = false;
bool stop = false;
std::string dest_string, src_string;
[[noreturn]] void startProcessing() {
stop = false;
MySingletonStarted = true;
while(!stop) {
dest_string = src_string;
}
}
void stopProcessing() {
}
};
MySingleton *MySingleton::singleton = nullptr;
I had to remove the [[noreturn]] statement in the C++ singleton class.
Thanks to Richard Critten who commented (Add an answer and I'll accept it).
I have an Android app needs to reference and use some native C++ code. I'm an experienced Java dev, but my C++ is lacking. I'm struggling to get it to run. I'm getting the error below. If I change the name inside of loadLibrary, it crashes immediately, so I'm assuming that the load works fine. How do I fix this?
No implementation found for boolean com.example.myapplication.BamBridge.test() (tried Java_com_example_myapplication_BamBridge_test and Java_com_example_myapplication_BamBridge_test__)
public class BamBridge implements IBamBridge {
static {
System.loadLibrary("native-lib");
}
private native boolean test();
}
BAM.h:
#ifndef BAM_H
#define BAM_H
#define JNIIMPORT
#define JNIEXPORT __attribute__ ((visibility ("default")))
#define JNICALL
#include <set>
#include <vector>
#include <string>
extern "C" JNIEXPORT JNICALL bool test();
#endif
BAM.cpp
#include <cstdio>
#include <stdint.h>
#include <iostream>
#include <map>
#include "BAM.h"
#define SWAP_UINT16(val) ((val << 8) | (val >> 8))
JNIEXPORT JNICALL bool test()
{
return true;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.6.0)
add_library( # Specifies the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/BAM.cpp )
On the C side change your function name to
Java_com_example_myapplication_BamBridge_test
As java searches for the function in the specific format.
In your Header file:
extern "C"
{
JNIEXPORT jboolean JNICALL Java_com_example_myapplication_BamBridge_test(JNIEnv *, jobject);
}
In your CPP file:
extern "C"
{
jboolean Java_com_example_myapplication_BamBridge_test(JNIEnv * env, jobject this)
{
return true;
}
}
I am using NDK in my android app . There was no problem . Here is the code for c++ file
#include <jni.h>
#include <string>
#include <stdio.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_examples_core_MyApplication_getKeyJNI(
JNIEnv *env,
jobject /* this */) {
std::string secret_key = "mysecret";
return env->NewStringUTF(secret_key.c_str());
}
Edit
Here is my approach
my native-lib.cpp
#include <jni.h>
#include <string>
#include <unistd.h> // for getcwd()
#include <iostream>
#include <stdio.h>
#include "constants.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_examples_core_MyApplication_getKeyJNI(
JNIEnv *env,
jobject /* this */) {
std::string secret_key = secret_key;
return env->NewStringUTF(secret_key.c_str());
}
my constants.h
#pragma once
#include <string>
extern const std::string secret_key; // declaration
my constants.cpp
#include "constants.h"
const std::string secret_key = "mysecret"; // definition
When I compile I get the following error
native-lib.cpp:13: undefined reference to `secret_key'
You don't want to put the definition in a header file, as that could lead to multiple definitions of the same variable.
But you could do something like this:
constants.h
#pragma once
#include <string>
extern const std::string secret_key; // declaration
constants.cpp
#include "constants.h"
const std::string secret_key = "mysecret"; // definition
main.cpp
#include <iostream>
#include "constants.h"
int main()
{
std::cout << secret_key; // usage
}
I'm working in an Android project with c++ files (NDK) but i have faced a problem
native method not found , when i add the
extern "C" {
} i got new problem which is declaration of c function '..' conflicts with .h previous declaration
here is my code
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_marwen_parojet_ocr_2_PostPhot */
#ifndef _Included_com_marwen_parojet_ocr_2_PostPhot
#define _Included_com_marwen_parojet_ocr_2_PostPhot
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_marwen_parojet_ocr_2_PostPhot
* Method: Traiter
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_marwen_parojet_1ocr_12_PostPhot_Traiter
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
this traitement_jni.h
and the .cpp file is
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv/cv.h>
#include "opencv2/ml/ml.hpp"
#include <android/log.h>
#include <jni.h>
#include "traitement_jni.h"
#include <stdlib.h>
extern "C" {
JNIEXPORT void JNICALL Java_com_marwen_parojet_1ocr_12_PostPhot_Traiter(JNIEnv* env, jobject,jstring path){
...
}
}
It seems you are passing a jclass in the declaration but a jobject in the definition. If these two types aren't aliases for the same type, this doensn't work: you cannot overload extern "C" functions.
header file:
extern "C" {
JNIEXPORT void JNICALL Java_com_marwen_parojet_1ocr_12_PostPhot_Traiter(
JNIEnv *,
jclass, // <---- here
jstring);
}
source file:
...
extern "C" {
JNIEXPORT void JNICALL Java_com_marwen_parojet_1ocr_12_PostPhot_Traiter(
JNIEnv* env,
jobject, // <---- here
jstring path){
...
}
}
android project:
i HAve c. file :
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <com_jp_algi_Corelib.h>
/* Header for class com_jp_algi_Corelib */
#ifdef __cplusplus
#define EXTCFUNC extern "C"
#elseif
#define EXTCFUNC extern
#endif
JNIEXPORT jfloatArray JNICALL Java_com_jp_algi_Corelib_vector
(JNIEnv * env, jobject clazz, jfloatArray input){
jfloatArray result;
}
jfloat* flt1 = env->GetFloatArrayElements(input,0)
;insiperd by : Eiegen android in the stackflow.
and there is some error:
C:/AA/FileBroswerActivity/jni/com_jp_algi_Corelib.c:23: error: 'env' undeclared here (not in a function)
C:/AA/FileBroswerActivity/jni/com_jp_algi_Corelib.c:23: error: 'input' undeclared here (not in a function)
/cygdrive/c/android-ndk-r5c/build/core/build-binary.mk:217: recipe for target `/cygdrive/c/AA/FileBroswerActivity/obj/local/armeabi/objs/com_jp_algi_Corelib/com_jp_algi_Corelib.o' failed
make: *** [/cygdrive/c/AA/FileBroswerActivity/obj/local/armeabi/objs/com_jp_algi_Corelib/com_jp_algi_Corelib.o] Error 1
16:52:03 Build Finished (took 672ms)
Your post is really unclear but your files should looks like this
.h file:
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
jfloatArray JNICALL Java_com_jp_algi_Corelib_vector(JNIEnv * env, jobject clazz, jfloatArray input);
#ifdef __cplusplus
}
#endif
.cpp file:
#include "yourheader.h"
#ifdef __cplusplus
extern "C" {
#endif
jfloatArray JNICALL Java_com_jp_algi_Corelib_vector(JNIEnv * env, jobject clazz, jfloatArray input)
{
jfloat* flt1 = env->GetFloatArrayElements(input,0);
}
#ifdef __cplusplus
}
#endif
Edit(after your edit):
jfloat* flt1 = env->GetFloatArrayElements(input,0);
is outside function body