I am trying to build the following in Netbean using c++. However I am unable to do so. I receive the following error.
gcc -shared -m32 -o dist/libJNIDemoCdl.so
build/Debug/Cygwin-Windows/JNIDemo.o -mno-cygwin -shared gcc: error:
unrecognized command line option ‘-mno-cygwin’
I am only able to build this manually using the following command
gcc -shared -o dist/libJNIDemoCdl.so
build/Debug/Cygwin-Windows/JNIDemo.o -Wall -D_JNI_IMPLEMENTATION_
-Wl,--kill-at
How do I fix this issue with the netbean IDE?
Header file
#include <stdint.h>
#include <jni.h>
/* Header for class jnidemojava_Main */
#ifndef _Included_jnidemojava_Main
#define _Included_jnidemojava_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: jnidemojava_Main
* Method: nativePrint
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_jnidemojava_Main_nativePrint
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Source
#include <jni.h>
#include <stdio.h>
#include "JNIDemoJava.h"
JNIEXPORT void JNICALL Java_jnidemojava_Main_nativePrint
(JNIEnv *env, jobject obj)
{
printf("\nHello World from C\n");
}
Cygwin and gcc removed the deprecated support of -mno-cygwin flag.
It seems you are using and old version of gcc, update your gcc version to GCC >=4.3
Or follow this guide and remove -mno-cygwin flag manually from your builtin toolchain descriptors
Related
I have a Java code ServiceTest.java that invokes JNI code buildCache() to build the cache. This codes compiled and exceuted correctly on Ubuntu; however, on centos I compiled and exceuted and got this error.
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.test.app.ServiceTest.buildCache()V
at com.test.app.ServiceTest.buildCache(Native Method)
at com.test.app.ServiceTest.<init>(ServiceTest.java:15)
at com.test.app.ServiceTest.main(ServiceTest.java:47)
Looks like, it was able to load the so file, but it is not able to invoke the method.
ServiceTest.java
public class ServiceTest{
static {
System.loadLibrary("cacheService");
}
public ServiceTest() {
buildCache();
}
private native void buildCache();
}
libcacheService.so is placed in /usr/local/lib64. I have gcc 9 and jdk 1.8
and have set LD_LIBRARY_PATH=/usr/local/ and export $LD_LIBRARY_PATH.
Any idea on how to debug?
******Adding below simple testcode******
1.
public class Test{
static {
System.loadLibrary("greet");
}
Test(){
}
public static void main(String...s){
Test t = new Test();
System.out.println(t.greetings());
}
private native String greetings();
}
javah Test -> Test.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> /* Header for class Test */
#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Test
* Method: greetings
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Test_greetings
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Greetings.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "Test.h"
using namespace std;
class Test{
JNIEXPORT jstring JNICALL Java_Test_greetings(JNIEnv *env, jobject thisObject){
jstring result = env->NewStringUTF("hi from JNI");
return result;
}
};
g++ --std=c++17 -g -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared -o greetings.so Greetings.cpp
$JAVA_HOME/bin/java -Djava.library.path=/lib64 Test
again same issue
Exception in thread "main" java.lang.UnsatisfiedLinkError: Test.greetings()Ljava/lang/String;
at Test.greetings(Native Method)
at Test.main(Test.java:13)
With same GCC 9 and jdk 1.8
Your Greetings.cpp should not include class Test:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "Test.h"
using namespace std;
JNIEXPORT jstring JNICALL Java_Test_greetings(JNIEnv *env, jobject thisObject){
jstring result = env->NewStringUTF("hi from JNI");
return result;
}
Then, the Java statement System.loadLibrary("greet"); expects to find a libgreet.so in its java.library.path, so compile it as follows:
g++ --std=c++17 -g -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared -o libgreet.so Greetings.cpp
Next, verify that the symbol is named exactly like the function, ie nm libgreet.so | grep Java_Test_greetings should produce output like the following:
0000000000000f20 T _Java_Test_greetings
Finally, run your Java program with the correct java.library.path.
The problem is that native library does not define a method that matches the signature of the Java native method; i.e. method name or signature in the JNI code is wrong ... or maybe it isn't a JNI native library at all.
I am trying to create shared library which is implementing JNI(Java Native Interface). My shared library is using another shared library which is named libPosAPI.so. But my shared library not correctly linking shared functions of libPosAPI.so.
In an implementation cpp, i am trying to use function vatps::PosAPI::sendData() of libPosAPI.so. Here is my build command:
g++ -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -I. -shared -o libPosAPIJni.so main_ubp_pos_PosAPIJni.cpp
It compiles successfully. Even it does not ask to provide libPosAPI.so with linker. But when use output shared library(libPosAPIJni.so), it gives following error undefined symbol: _ZN5vatps6PosAPI8sendDataB5cxx11Ev. I also provided libPosAPI.so with -L -l options. The result is same.
Here is my header file. That is a result of javac -h PosAPIJni.java.
main_ubp_pos_PosAPIJni.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class main_ubp_pos_PosAPIJni */
#ifndef _Included_main_ubp_pos_PosAPIJni
#define _Included_main_ubp_pos_PosAPIJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: main_ubp_pos_PosAPIJni
* Method: sendData
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_main_ubp_pos_PosAPIJni_sendData
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
main_ubp_pos_PosAPIJni.cpp
#include "main_ubp_pos_PosAPIJni.h"
#include "PosAPI.h" // header file of libPosAPI.so
#include <iostream>
using namespace std;
inline string jstring_to_string(JNIEnv* env, jstring string) {
string value;
....
}
// IMPLEMENTATIONS
JNIEXPORT jstring JNICALL Java_main_ubp_pos_PosAPIJni_sendData(JNIEnv* env,
jclass cls) {
string res_sendData = vatps::PosAPI::sendData(); // The PROBLEM IS HERE!!. trying to use function of libPosAPI.so. declared in PosAPI.h
return string_to_jstring(env, res_sendData);
}
The output of nm command of two shared libraries:
nm -D libPosAPI.so | grep sendData :
000000000000c3e0 T sendData
000000000000a8dc T _ZN5vatps6PosAPI8sendDataEv
nm -u libPosAPIJni.so | grep sendData:
U _ZN5vatps6PosAPI8sendDataB5cxx11Ev
Please direct me right way :)
Let's decode your symbol:
$ c++filt _ZN5vatps6PosAPI8sendDataB5cxx11Ev
vatps::PosAPI::sendData[abi:cxx11]()
So, your code expects sendData with std::string with C++11 ABI, whereas libPosAPI.so provides sendData with pre-C++11 ABI std::string.
abi:cxx11 hints to GCC5 and the C++11 ABI:
Users that depend on third-party libraries or plugin interfaces that still use the old ABI can build their code with -D_GLIBCXX_USE_CXX11_ABI=0 and everything should work fine. In most cases, it will be obvious when this flag is needed because of errors from the linker complaining about unresolved symbols involving __cxx11.
I tried to link a static library (compiled with gcc) to a c++ program and I got 'undefined reference'. I used gcc and g++ version 4.6.3 on a ubuntu 12.04 server machine. For example, here is the simple library file for factorial method:
mylib.h
#ifndef __MYLIB_H_
#define __MYLIB_H_
int factorial(int n);
#endif
mylib.c
#include "mylib.h"
int factorial(int n)
{
return ((n>=1)?(n*factorial(n-1)):1);
}
I created object for this mylib.c using gcc:
gcc -o mylib.o -c mylib.c
Again the static library was created from the object file using AR utility:
ar -cvq libfact.a mylib.o
I tested this library with a C program (test.c) and C++ program (test.cpp)
Both C and C++ program have the same body:
#include "mylib.h"
int main()
{
int fact = factorial(5);
return 0;
}
Assuming static library libfact.a is available in /home/test directory, I compiled my C program without any issues:
gcc test.c -L/home/test -lfact
However while testing C++ program, it threw a link error:
g++ test.cpp -L/home/test -lfact
test.cpp:(.text+0x2f): undefined reference to `factorial(int)'
collect2: ld returned 1 exit status
I even tried adding extern command in test.cpp:
extern int factorial(int n) //added just before the main () function
Still the same error.
Can someone tell me what I am wrong here?
Is there anything I missed while creating the static library?
Do I have to add anything in my test.cpp to make it work?
The problem is that you haven't told your C++ program that factorial is written in C. You need to change your test.h header file. Like this
#ifndef __MYLIB_H_
#define __MYLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int factorial(int n);
#ifdef __cplusplus
}
#endif
#endif
Now your header file should work for both C and C++ programs. See here for details.
BTW names containing a double underscore are reserved for the compliler (so are names starting with an underscore and a capital letter) so #ifndef __MYLIB_H_ is illegal strictly speaking. I would change to #ifndef MYLIB_H #define MYLIB_H
While the accepted answer is absolutely correct, I thought I'd just add an observation. Some editors have trouble with the open / close brace, and will indent the entire extern "C" scope in the header. If mylib.h is a key header for a library, you might consider:
#if defined (__cplusplus)
#define _MYLIB_INIT_DECL extern "C" {
#define _MYLIB_FINI_DECL }
#else
#define _MYLIB_INIT_DECL
#define _MYLIB_FINI_DECL
#endif
All other headers in mylib library, e.g., mylib_aux.h, can be of the form:
#ifndef _MYLIB_AUX_H
#define _MYLIB_AUX_H
#include <mylib.h>
_MYLIB_INIT_DECL
... header content ...
_MYLIB_FINI_DECL
#endif /* _MYLIB_AUX_H */
Obviously, the names I'm using are arbitrary, but for multiple library headers, this approach has been useful to me.
I've looked around on stackoverflow for similar problems, but none of the solutions I've found seem to be working for me. I am on a Linux/Ubuntu machine. I'm just practising JNI but I get this error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: nativetest.sayHello(Ljava/lang/String;)Ljava/lang/String;
at nativetest.sayHello(Native Method)
at nativetest.main(nativetest.java:8)
I have provided my .c, .h, and .java file.
.java file:
public class nativetest
{
System.loadLibrary("nativetest");
public native String sayHello(String s);
public static void main(String[] argv)
{
String retval = null;
nativetest nt = new nativetest();
retval = nt.sayHello("Hi");
System.out.println("Invocation returned " + retval);
}
}
.c file:
#include "nativetest.h"
#include <stdio.h>
#include <jni.h>
#include <stdlib.h>
JNIEXPORT jstring JNICALL Java_nativetest_sayHello(JNIEnv *env, jobject thisobject, jstring js)
{
return js;
}
.h file:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class nativetest */
#ifndef _Included_nativetest
#define _Included_nativetest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: nativetest
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_nativetest_sayHello
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
I used these commands to generate the .h file, compile/generate the .so file, and run:
javac nativetest.java
javah -jni nativetest
gcc --shared -o libnativetest.so -I/usr/lib/jvm/java-7-openjdk-amd64/include -I/usr/lib/jvm/java-7-openjdk-amd64/include/linux nativetest.c
java -Djava.library.path=. nativetest
I am currently in the directory with the libnativetest.so file and all my .c, .java, and .h files.
Any help would be appreciated.
Okay, turns out the call to
System.loadLibrary("nativetest");
should be static:
static{
System.loadLibrary("nativetest");
}
I was also making mistakes on recompiling using javac. I am quite new to Linux :)
I have a C function that I would like to call from C++. I couldn't use "extern "C" void foo()" kind of approach because the C function failed to be compiled using g++. But it compiles fine using gcc. Any ideas how to call the function from C++?
Compile the C code like this:
gcc -c -o somecode.o somecode.c
Then the C++ code like this:
g++ -c -o othercode.o othercode.cpp
Then link them together, with the C++ linker:
g++ -o yourprogram somecode.o othercode.o
You also have to tell the C++ compiler a C header is coming when you include the declaration for the C function. So othercode.cpp begins with:
extern "C" {
#include "somecode.h"
}
somecode.h should contain something like:
#ifndef SOMECODE_H_
#define SOMECODE_H_
void foo();
#endif
(I used gcc in this example, but the principle is the same for any compiler. Build separately as C and C++, respectively, then link it together.)
Let me gather the bits and pieces from the other answers and comments, to give you an example with cleanly separated C and C++ code:
The C Part:
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
void foo(void)
{
/* ... */
}
Compile this with gcc -c -o foo.o foo.c.
The C++ Part:
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
void bar() {
foo();
}
Compile this with g++ -c -o bar.o bar.cpp
And then link it all together:
g++ -o myfoobar foo.o bar.o
Rationale:
The C code should be plain C code, no #ifdefs for "maybe someday I'll call this from another language". If some C++ programmer calls your C functions, it's their problem how to do that, not yours. And if you are the C++ programmer, then the C header might not be yours and you should not change it, so the handling of unmangled function names (i.e. the extern "C") belongs in your C++ code.
You might, of course, write yourself a convenience C++ header that does nothing except wrapping the C header into an extern "C" declaration.
I agree with Prof. Falken's answer, but after Arne Mertz's comment I want to give a complete example (the most important part is the #ifdef __cplusplus):
somecode.h
#ifndef H_SOMECODE
#define H_SOMECODE
#ifdef __cplusplus
extern "C" {
#endif
void foo(void);
#ifdef __cplusplus
}
#endif
#endif /* H_SOMECODE */
somecode.c
#include "somecode.h"
void foo(void)
{
/* ... */
}
othercode.hpp
#ifndef HPP_OTHERCODE
#define HPP_OTHERCODE
void bar();
#endif /* HPP_OTHERCODE */
othercode.cpp
#include "othercode.hpp"
#include "somecode.h"
void bar()
{
foo(); // call C function
// ...
}
Then you follow Prof. Falken's instructions to compile and link.
This works because when compiling with gcc, the macro __cplusplus is not defined, so the header somecode.h included in somecode.c is like this after preprocessing:
void foo(void);
and when compiling with g++, then __cplusplus is defined, and so the header included in othercode.cpp is now like that:
extern "C" {
void foo(void);
}
This answer is inspired by a case where Arne's rationale was correct. A vendor wrote a library which once supported both C and C++; however, the latest version only supported C. The following vestigial directives left in the code were misleading:
#ifdef __cplusplus
extern "C" {
#endif
This cost me several hours trying to compile in C++. Simply calling C from C++ was much easier.
The ifdef __cplusplus convention is in violation of the single responsibility principle. A code using this convention is trying to do two things at once:
(1) execute a function in C
-- and --
(2) execute the same function in C++
It's like trying to write in both American and British English at the same time. This is unnecessarily throwing an #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #else a useless tool which makes the code harder to read #endif into the code.
For simple code and small libraries the ifdef __cplusplus convention may work; however, for complex libraries it is best to pick one language or the other and stick with it. Supporting one of the languages will take less maintenance than trying to support both.
This is a record of the modifications I made to Arne's code to get it to compile on Ubuntu Linux.
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
#include <stdio.h>
void foo(void)
{
// modified to verify the code was called
printf("This Hello World was called in C++ and written in C\n");
}
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
int main() {
foo();
return(0);
}
Makefile
# -*- MakeFile -*-
# dont forget to use tabs, not spaces for indents
# to use simple copy this file in the same directory and type 'make'
myfoobar: bar.o foo.o
g++ -o myfoobar foo.o bar.o
bar.o: bar.cpp
g++ -c -o bar.o bar.cpp
foo.o: foo.c
gcc -c -o foo.o foo.c