I started looking into Java's JNI feature. I followed this [tutorial][1]. So my class goes like this :
package me.gagan.pheonix.natve;
public class HelloJNI {
static {
System.loadLibrary("hello");
}
private native void sayHello();
public static void main(String... args) {
new HelloJNI().sayHello();
}
}
HelloJNI.c file like this:
\#include <jni.h>
\#include <stdio.h>
\#include "me_gagan_pheonix_natve_HelloJNI.h"
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("Hello World in native C!\n");
return;
}
My directory structure is:
<pre>
C:.
├───bin
│ ├───me
│ │ └───gagan
│ │ └───pheonix
│ │ └───natve
│ │ └───HelloJNI.class
│ ├───resources
│ │ └───hello.dll
│ ├───me_gagan_pheonix_natve_HelloJNI.h
│ └───HelloJNI.c
└───src
├───me
│ └───gagan
│ └───pheonix
│ └───natve
│ └───HelloJNI.java
└───resources
</pre>
I also added
-Djava.library.path=C:\Gagan\workspace\Pheonix\bin\resources
But still error is coming. Any idea what is going wrong. Followed each step correctly.
Following commands worked for me
gcc -Wl,--add-stdcall-alias -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -shared -o hello.dll HelloJNI.c
echo %JAVA_HOME%
C:\Java\jdk1.6.0_45
javah -verbose -jni -classpath . me.gagan.pheonix.natve.HelloJNI
EDIT:
Exception encountered is :
Exception in thread "main" java.lang.UnsatisfiedLinkError: me.gagan.pheonix.natve.HelloJNI.sayHello()V
at me.gagan.pheonix.natve.HelloJNI.sayHello(Native Method)
at me.gagan.pheonix.natve.HelloJNI.main(HelloJNI.java:12)
[1]: https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
Hi anybody having any suggestions ??
package me.gagan.pheonix.natve;
public class HelloJNI {
...
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
You've changed the package name after you generated the .h file with javah. Do it again, and adjust the function name in the .c file accordingly, to agree with the declaration in the .h file.
Related
This question already has answers here:
Automatically add all files in a folder to a target using CMake?
(5 answers)
Closed 11 months ago.
I'm trying to set up a C++ project using CMake but I think I'm missing something. When I'm trying to use my library in an executable I get the error:
Scanning dependencies of target dynamic-shadows-lib
[ 33%] Linking CXX static library libdynamic-shadows-lib.a
[ 33%] Built target dynamic-shadows-lib
Scanning dependencies of target main
[ 66%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
/usr/bin/ld: CMakeFiles/main.dir/main.cpp.o: in function `main':
main.cpp:(.text+0x83): undefined reference to `num3()'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/main.dir/build.make:85: main] Error 1
make[1]: *** [CMakeFiles/Makefile2:78: CMakeFiles/main.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
My file structure looks like this:
.
├── build
├── CMakeLists.txt
├── include
│ └── vec2f.hpp
├── main.cpp
└── src
└── vec2f.cpp
3 directories, 4 files
My root (and only) CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.16)
project(
dynamic-shadows
VERSION 1.0
LANGUAGES CXX
)
# Set C++ to version 14
set(CMAKE_CXX_STANDARD 14)
# Set a name for the target
set(TARGET_LIB ${CMAKE_PROJECT_NAME}-lib)
# Make library ${TARGET_LIB}
add_library(${TARGET_LIB} STATIC)
# Set linker language to CXX (Gets error without it)
set_target_properties(${TARGET_LIB} PROPERTIES LINKER_LANGUAGE CXX)
# Set include directory for ${TARGET_LIB}
target_include_directories(
${TARGET_LIB}
PUBLIC
${PROJECT_SOURCE_DIR}/include
)
# Set sources for ${TARGET_LIB}
target_sources(
${TARGET_LIB}
PUBLIC
${PROJECT_SOURCE_DIR}/src
)
# Add a simple test executable to test the library
add_executable(main main.cpp)
# Link the ${TARGET_LIB} to main executable
target_link_libraries(
main
PUBLIC
${TARGET_LIB}
)
I suspect the problem lies in my CMakeLists.txt since I'm new to this, but I can't figure out what it is. What am I missing? Could it be something else I'm doing wrong?
The code I'm trying to run is very simple but I'll include it for reference:
./include/vec2.hpp
#ifndef __VEC2F_HPP__
#define __VEC2F_HPP__
#include <iostream>
namespace ds {
class vec2f {
public:
float x;
float y;
vec2f(float x_value, float y_value) : x(x_value), y(y_value) {}
};
} // End of namespace ds
std::ostream & operator<<(std::ostream &out, const ds::vec2f &v);
ds::vec2f operator+(const ds::vec2f &left, const ds::vec2f &right);
float num3();
#endif
./src/vec2f.cpp
#include "../include/vec2f.hpp"
/**
* #brief Overload of << operator for ds::vec2f class to allow for printing it in std::cout.
*
* #param out std::ostream reference (&)
* #param v ds::vec2f reference (&)
* #return std::ostream& out
*/
std::ostream & operator<<(std::ostream &out, const ds::vec2f &v)
{
return out << "[" << v.x << ", " << v.y << "]";
}
/**
* #brief Overload of + operator for ds::vec2f class to allow for vector addition.
*
* #param left ds::vec2f
* #param right ds::vec2f
* #return ds::vec2f sum
*/
ds::vec2f operator+(const ds::vec2f &left, const ds::vec2f &right)
{
return ds::vec2f(
left.x + right.x,
left.y + right.y
);
}
float num3()
{
return 3;
}
./main.cpp
#include "vec2f.hpp"
int main(int argc, char* argv[])
{
std::cout << "Hello world!" << std::endl;
ds::vec2f v1 = ds::vec2f(8, -2);
ds::vec2f v2 = ds::vec2f(2, 5);
float n = num3();
std::cout << "Res: " << n << std::endl;
return 0;
}
I've tried to follow solutions to similair problems which usually seems to have something to do with linking.
Most havn't really helped since I'm required to solve this using CMake. I've tried with a variety of CMakeLists.txt configurations but ended up with this one since it looked the cleanest and seemed to be using the latest implementations of commands (target_include_directory instead of include_directories etc..)
# Set sources for ${TARGET_LIB}
target_sources(
${TARGET_LIB}
PUBLIC
${PROJECT_SOURCE_DIR}/src
)
You add source files, not directories. Just:
add_library(... STATIC
src/vec2f.cpp
)
Do not use PROJECT_SOURCE_DIR, it will change when someone does add_subirectory from above. If you want current project source dir, thats ${CMAKE_CURRENT_SOURCE_DIR}.
# Set linker language to CXX (Gets error without it)
set_target_properties(${TARGET_LIB} PROPERTIES LINKER_LANGUAGE CXX)
Remove it. Yes, without source files, no one knows what language your library is in.
I'm developing a C++ library and wanted to interface it with both Python and R.
The core idea is that R and Python are basically 'empty shells' used for plotting and not much else and all the core computation is done in C++, so that the interface is just a bunch of functions that run the equivalent of a C++ 'main' and return the output to R or Python instead of saving stuff to file.
My idea was to use goolge's protocol buffer in a server/client fashion: data is passed from Python (R) to C++ using a serialized message, is then deserialized in C++. Computation is run in C++ and to Python (R) is returned a list of bytes/strings corresponding each to a serialized proto object.
In Python, this works like a charm thanks to Pybind11.
However, in R I get a weird error:
/usr/include/google/protobuf/arena_impl.h:174:60: error: macro "Free" passed 3 arguments, but takes just 1
void (*block_dealloc)(void*, size_t));
I believe this issue is due to Rcpp defining a similar macro to protobuf.
The following MWE reproduces the same error.
This is the fold structure
.
├── src
│ ├── rcpp_exports.cpp
├── student.proto
└── test.R
in test.R
Rcpp::sourceCpp(file="src/rcpp_exports.cpp")
in rcpp_exports.cpp
#include <Rcpp.h>
using namespace Rcpp;
#include "student.pb.h"
// [[Rcpp::export]]
std::string foo() {
Student stud;
stud.set_grade(25);
return stud.DebugString();
}
in student.proto
syntax = "proto3";
message Student {
double grade = 1;
bool pass = 2;
}
the protobuf file is then compiled using
> protoc --proto_path=. --cpp_out=./src student.proto
and finally I run the test.R file
> Rscript test.R
Getting the following error log:
In file included from /usr/include/google/protobuf/arena.h:55:0,
from /home/mario/dev/tesi/test_rproto/src/student.pb.h:24,
from rcpp_exports.cpp:3:
/usr/include/google/protobuf/arena_impl.h:174:60: error: macro "Free" passed 3 arguments, but takes just 1
void (*block_dealloc)(void*, size_t));
^
In file included from /usr/share/R/include/R.h:91:0,
from /home/mario/R/x86_64-pc-linux-gnu-library/3.6/Rcpp/include/Rcpp/r/headers.h:63,
from /home/mario/R/x86_64-pc-linux-gnu-library/3.6/Rcpp/include/RcppCommon.h:29,
from /home/mario/R/x86_64-pc-linux-gnu-library/3.6/Rcpp/include/Rcpp.h:27,
from rcpp_exports.cpp:1:
/usr/share/R/include/R_ext/RS.h:74:37: error: expected identifier before ‘(’ token
#define Free(p) (R_chk_free( (void *)(p) ), (p) = NULL)
^
/usr/share/R/include/R_ext/RS.h:74:47: error: ‘parameter’ declared as function returning a function
#define Free(p) (R_chk_free( (void *)(p) ), (p) = NULL)
^
/usr/share/R/include/R_ext/RS.h:74:50: error: expected ‘)’ before ‘,’ token
#define Free(p) (R_chk_free( (void *)(p) ), (p) = NULL)
^
make: *** [rcpp_exports.o] Error 1
I would recommend a few things for defensive programming:
Do not flatten namespaces i.e. remove using namespace Rcpp; and call your functins explicitly with prefix.
Ask for stringent includes (which we can't retroactively make a default) by defining #define STRICT_R_HEADERS before including Rcpp.h or other R headers.
Use R functions without the remap, i.e Rf_error() by defining R_NO_REMAP but Rcpp should do that for you.
That should avoid the clash you found here by being a little liberal in what you included and how.
Lastly, we wrote RProtoBuf (and it actually had a hand in creating what is the current Rcpp too) well over a decade ago yet I never got that error message you have here. So it clearly can be avoided.
I am trying to include gtest to my project.
The problem is that I get a undefined reference error in the GTest.
I am trying to test the Node class in Gtest. Inside the constructor of the Node I am using the Class Logger. Although I have added the library logger to the gtest-target I still the undefined reference error regarding to the Logger....
My guess CMake does no look for nested classes that are used inside Node.
only Node itself.
Temperoy fix
If I use the Logger in the gtest-node.cpp it works
gtest.cpp
/* Pseudo Code */
TEST Node
{
Logger::log("Temp Fix")
Node * n = Node(0,0,0)
}
This way the the Logger is directly used in the gtest this way the logger-library will be add to the target by cmake.
My Setup (pseudo-code because my project is way bigger than this)
(https://github.com/ronsalm/LearningLunch)
├── CMakeLists.txt
├── main.cpp
├── logger
│ ├── CMakeLists.txt
│ ├── logger.cpp
│ └── logger.h
├── Node
│ ├── CMakeLists.txt
│ ├── node.cpp
│ └── node.h
└── Gtest
├── CMakeLists.txt
├── gtest-node.cpp
└── node.h
main.cpp
/* Pseudo Code */
int main()
{
Node * n = Node(0,0,0)
}
logger.h
/* Pseudo Code */
class Logger
{
log(string)
}
logger.cpp
/* Pseudo Code */
Logger::log(string s)
{
//write to string to file
}
node.h
/* Pseudo Code */
class Node
{
Node(int,int,int)
}
node.cpp
/* Pseudo Code */
Node::node(int x, int y , int z)
{
Logger::log("Create Node")
}
gtest.cpp
/* Pseudo Code */
TEST Node
{
Node * n = Node(0,0,0)
}
CMakeLists.txt (Root)
project(applic)
include_directories(
"${CMAKE_SOURE_DIR/node"
"${CMAKE_SOURE_DIR/logger")
add_library(node node.cpp)
add_executable(applic main.cpp)
target_link_libraries(applic logger node)
CMakeLists.txt (Logger)
add_library(logger logger.cpp)
CMakeLists.txt (Node)
add_library(node node.cpp)
CMakeLists.txt (Gtest)
add_executable(gtest-node gtest-node.cpp)
set_target_properties(gtest-node PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
target_link_libraries(gtest-logger gtest phtread logger node)
add_test(NAME node COMMAND $<TARGET_FILE:gtest-node>
enable_testing()
The original error:
../../../../lib/libdatabase.a(sql.cpp.o): In function `SQL::Open()':
/home/rsalm/test/src/database/sql/sql.cpp:19: undefined reference to `Logger::TagDebug'
/home/rsalm/test/src/database/sql/sql.cpp:19: undefined reference to `Logger::instance(std::string const&) '
../../../../lib/libdatabase.a(sql.cpp.o): In function `SQL::Close()':
/home/rsalm/test/src/database/sql/sql.cpp:27: undefined reference to `Logger::TagDebug'
/home/rsalm/test/src/database/sql/sql.cpp:27: undefined reference to `Logger::instance(std::string const&) '
../../../../lib/libdatabase.a(sql.cpp.o): In function `Logger& operator<< <char [25]>(Logger&, char const (&) [25]) ':
/home/rsalm/test/inc/logger.h:33: undefined reference to `Logger::pInstance'
../../../../lib/libdatabase.a(sql.cpp.o): In function `Logger& operator<< <char [21]>(Logger&, char const (&) [21]) ':
/home/rsalm/test/inc/logger.h:33: undefined reference to `Logger::pInstance'
../../../../lib/libdatabase.a(sql.cpp.o): In function `Logger& operator<< <char [26]>(Logger&, char const (&) [26]) ':
/home/rsalm/test/inc/logger.h:33: undefined reference to `Logger::pInstance'
../../../../lib/libdatabase.a(sql.cpp.o): In function `Logger& operator<< <char [24]>(Logger&, char const (&) [24]) ':
/home/rsalm/test/inc/logger.h:33: undefined reference to `Logger::pInstance'
collect2: error: ld returned 1 exit status
src/layout/gtest/CMakeFiles/gtest-layout-factory.dir/build.make:98: recipe for target '../bin/gtest-layout-factory' failed
make[2]: *** [../bin/gtest-layout-factory] Error 1
CMakeFiles/Makefile2:1824: recipe for target 'src/layout/gtest/CMakeFiles/gtest-layout-factory.dir/all' failed
Your node library uses the logger library, but you haven't specified that link relationship. You need to add the following:
target_link_library(node PRIVATE logger)
Then, any time you link to node, CMake will append logger to the link libraries if node is built as a static library.
You almost get away with what you did with the linking of the gtest-logger target where you explicitly added the logger library there, assuming you actually meant gtest-node rather than gtest-logger in that call to target_link_library(). If you had listed logger after node, I would have expected the build to work (assuming the target name typo), but that would not be the correct way to do it. You should only need to explicitly list logger as a link dependency of gtest-logger if something in gtest.cpp directly referenced something from the Logger class.
I have the following c++ code for testing:
#include <lua.hpp>
#include <iostream>
static int dummy(lua_State * L)
{
std::cout << "Test";
return 0;
}
int luaopen_testlib(lua_State * L)
{
lua_register(L,"dummy",dummy);
return 0;
}
I compile it with commands and it gives me no errors:
g++ -Wextra -O2 -c -o testlib.o main.cpp
g++ -shared -o testlib.so testlib.o
But when i try to load it in lua i get undefined symbol error as this:
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> require"testlib"
error loading module 'testlib' from file './testlib.so':
./testlib.so: undefined symbol: _Z16lua_pushcclosureP9lua_StatePFiS0_Ei
It seems for me that there is something missing in the g++ commands, but i have been searching solution for whole morning and can't get this simple example to compile.
EDIT:
after few recompilations it returned to:
error loading module 'testlib' from file './testlib.so':
./testlib.so: undefined symbol: luaopen_testlib
which was solved by adding :
extern "C"
{
int luaopen_testlib(lua_State *L)
{
lua_register(L,"dummy",dummy);
return 0;
}
}
The Lua binary is compiled as C code, the library tries to use it as C++. That will not work as C++ does name mangling to support overloading. As C does not support overloading it does not need the name mangling and will not understand mangled names.
The solution to this is to tell the C++ compiler that the Lua functions it is going to interact with are straight C and they need no name mangling.
Also the luaopen_testlib function must be extern "C" as it will be called from C code with no mangling.
extern "C" {
#include <lua.h>
}
#include <iostream>
static int dummy(lua_State * L)
{
(void)L;
std::cout << "Test"<<std::endl;
return 0;
}
extern "C"
int luaopen_testlib(lua_State * L)
{
lua_register(L,"dummy",dummy);
return 0;
}
I ran my test with Lua 5.4.2 and used the following commands to build the library:
g++ -Wall -Wextra -O2 -Isrc -c -fPIC -o testlib.o testlib.cpp
g++ -shared -o testlib.so testlib.o
Note the -Isrc is needed to find lua.h in my test setup and -fPIC was required to use cout in the library (but that may depend on the compiler version used).
and the result is:
Lua 5.4.2 Copyright (C) 1994-2020 Lua.org, PUC-Rio
> require 'testlib'
true ./testlib.so
> dummy
function: 0x7ff07d2a0aa0
> dummy()
Test
>
The Lua version used will, in this case, not make any difference.
Try to use Luabind. Here is the Hello World example
#include <iostream>
#include <luabind/luabind.hpp>
void greet()
{
std::cout << "hello world!\n";
}
extern "C" int init(lua_State* L)
{
using namespace luabind;
open(L);
module(L)
[
def("greet", &greet)
];
return 0;
}
This is how i would compile lua, is not exacly gcc but cmake can use gcc.
.
├── CMakeList.txt (A)
├── main.cpp
├── lua_535
│ ├── CMakeLists.txt (B)
│ └── * lua_content *
main.cpp | Just checks if it works
#include <iostream>
#include <string>
#include "lua.hpp"
int main(){
lua_State * lua = luaL_newstate();
std::string str_acction = "a = 5";
int res = luaL_dostring(lua, str_acction.c_str());
std::cout << "DS State > " << res << std::endl;
lua_close(lua);
return 0;
}
CMakeList.txt (A) | Creates the executable and links the library
cmake_minimum_required(VERSION 3.12)
project(lua_test)
add_executable(main main.cpp)
add_subdirectory("lua_535")
target_link_libraries(main PUBLIC lua_lib)
CMakeList.txt (B) | Joins Lua files into a library
Get the latest lua source files
Extract the content into a sub folder
Add this file into the folder
cmake_minimum_required(VERSION 3.12)
project( lua_lib )
set ( LUA_EMBEDDED ON )
set ( LUA_RUNTIME_MAIN "src/luac.c" )
set (LUA_RUNTIME_SOURCES
"src/lapi.c"
"src/lapi.h"
"src/lauxlib.c"
"src/lauxlib.h"
"src/lbaselib.c"
"src/lbitlib.c"
"src/lcode.c"
"src/lcode.h"
"src/lcorolib.c"
"src/lctype.c"
"src/lctype.h"
"src/ldblib.c"
"src/ldebug.c"
"src/ldebug.h"
"src/ldo.c"
"src/ldo.h"
"src/ldump.c"
"src/lfunc.c"
"src/lfunc.h"
"src/lgc.c"
"src/lgc.h"
"src/linit.c"
"src/liolib.c"
"src/llex.c"
"src/llex.h"
"src/llimits.h"
"src/lmathlib.c"
"src/lmem.c"
"src/lmem.h"
"src/loadlib.c"
"src/lobject.c"
"src/lobject.h"
"src/lopcodes.c"
"src/lopcodes.h"
"src/loslib.c"
"src/lparser.c"
"src/lparser.h"
"src/lprefix.h"
"src/lstate.c"
"src/lstate.h"
"src/lstring.c"
"src/lstring.h"
"src/lstrlib.c"
"src/ltable.c"
"src/ltable.h"
"src/ltablib.c"
"src/ltm.c"
"src/ltm.h"
"src/lua.c"
"src/lua.h"
"src/lua.hpp"
"src/luaconf.h"
"src/lualib.h"
"src/lundump.c"
"src/lundump.h"
"src/lutf8lib.c"
"src/lvm.c"
"src/lvm.h"
"src/lzio.c"
"src/lzio.h"
)
add_library( lua_lib "${LUA_RUNTIME_SOURCES}" )
if( NOT LUA_EMBEDDED)
add_library( lua_lib "${LUA_RUNTIME_MAIN}")
endif()
target_include_directories ( lua_lib PUBLIC "${PROJECT_SOURCE_DIR}/src")
If lua is enbedded src/luac.c should be excluded because conteins a int main(){}
I keep getting complaint from the g++ compiler that the following code has problems.
After careful examination, I still cannot figure out why it cannot find the constructor and destructor of class B from embedMain.cpp.
Can someone give me a little hint?
Thank you
// embedMain.cpp
#include "embed.h"
int main(void)
{
B b("hello world");
return 0;
}
,
// embed.h
#ifndef EMBED_H
#define EMBED_H
#include <string>
class B
{
public:
B(const std::string& _name);
~B();
private:
std::string name;
};
#endif
,
// embed.cpp
#include <iostream>
#include <string>
#include "embed.h"
B::B(const std::string& _name) : name(_name) {}
B::~B() {
std::cout << "This is B::~B()" << std::endl;
}
,
~/Documents/C++ $ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
~/Documents/C++ $ g++ -o embedMain embedMain.cpp
/tmp/ccdqT9tn.o: In function `main':
embedMain.cpp:(.text+0x42): undefined reference to `B::B(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
embedMain.cpp:(.text+0x6b): undefined reference to `B::~B()'
embedMain.cpp:(.text+0x93): undefined reference to `B::~B()'
collect2: ld returned 1 exit status
// Updated //
Based on comments from experts here, I have found the right way to link the embedMain.cpp with the embed library.
Here is the detail step:
user#ubuntu:~/Documents/C++$ tree
.
├── embed.cpp
├── embed.h
├── embedMain.cpp
user#ubuntu:~/Documents/C++$ g++ -Wall -c embed.cpp
user#ubuntu:~/Documents/C++$ ar -cvq libembed.a embed.o
user#ubuntu:~/Documents/C++$ g++ -o embedMain embedMain.cpp -L/home/user/Documents/C++ -lembed
user#ubuntu:~/Documents/C++$ tree
.
├── embed.cpp
├── embed.h
├── embedMain
├── embedMain.cpp
├── embed.o
├── libembed.a
You need to compile embed.cpp and link it into your executable, like so:
g++ -o embedMain embedMain.cpp embed.cpp
This compiles both files and links everything. To separate the three steps:
g++ -c embed.cpp
g++ -c embedMain.cpp
g++ -o embedMain embedMain.o embed.o
You also have to include embed.cpp in your compile/link.