I am trying to edit a static variable from an instance of another class. However, I get an error that says my static variable is an undefined symbol in my shared library.
staticClass.h
class staticClass{
public:
static int num; //declaration
}
staticClass.cpp
#include "staticClass.h"
int num = 0; //definition
... //some functions that use num
main.cpp
#include "staticClass.h"
#include <jni.h>
#include "main.h" //this is the header file for the JNI, I will not include this unless someone finds it necessary because all these variables are made up for clarity
JNIEXPORT jint JNICALL Java_main_foo(JNIEnv *env, jobject thisobj, jint someInt){
staticClass example;
int intIWant = (int)someint;
example.num = intIWant;
printf("%d\n",example.num);
}
this is the error message:
Exception in thread "main" java.lang.UnsatisfiedLinkError: .../libfoo.so: .../libfoo.so: undefined symbol: _ZN5staticClass9numE
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1935)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1860)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1850)
at java.lang.Runtime.loadLibrary0(Runtime.java:845)
at java.lang.System.loadLibrary(System.java:1084)
at tcr.<clinit>(tcr.java:9)
So yeah, I know how tricky UnsatisfiedLinkError can be but any help would be appreciated.
Wrong definition, in staticClass.cpp
Use
int staticClass::num = 0; // //definition
Related
So I've got this interface class that I include, both in the dll and the client project
// InterfaceClass.h
#pragma once
class InterfaceClass
{
public:
virtual void Update() = 0;
};
This is the dll class that calls one of its own methods inside update
// DLLClassThatDoesSomething.cpp
#include "InterfaceClass.h"
#include <iostream>
#include <string>
class __declspec(dllexport) DLLClass : public InterfaceClass
{
public:
void Update()
{
std::cout << this->GetString();
}
std::string& GetString()
{
std::string thestring = "bruhmoment";
return thestring;
}
};
extern "C"
{
__declspec(dllexport) InterfaceClass* CreateInstance()
{
return new DLLClass();
}
}
And this is the "Client" project
// main.cpp
#include "InterfaceClass.h"
#include <Windows.h>
typedef InterfaceClass* (__cdecl *Class) ();
int main()
{
HINSTANCE dll = LoadLibrary(L"DLLClass.dll");
Class klass = (Class)GetProcAddress(dll, "CreateInstance");
InterfaceClass* IKlass = klass();
IKlass->Update();
FreeLibrary(dll);
return 0;
}
The moment I call IKlass->Update() I get an exception for Access Memory Violation because of the DLLClass calling its own method.
I haven't tried anything since I barely know how to load a DLL on runtime and I've used this nifty tutorial
How can I let it call the method and not get thrown an exception? I'm trying to let ppl that will create mods for my game create their own mods with their custom classes for bosses, mobs and etc. in DLLs.
EDIT:
Turns out it was a syntax mistake on my end. Instead of return new DLLClass;, it had to be return new DLLClass();. After fixing it, it works as intended.
You return a reference to a local variable thestring, and by the time you try to access it in
std::cout << this->GetString(), referenced data is already destroyed. In fact, it is destroyed right after the end of enclosing scope of compound statement where the variable was declared.
It may "appear" to work sometimes due to the stack not being overwritten yet, but eventually it will fail miserably like it did in your case. This triggers UB (undefined behavior).
I am trying to run a main.cpp which access 3 different classes. For some reason, I am getting a unresolved external symbol error. From what I've seen online, its clearly a linking error somewhere, but I cannot find it. I've listed the error below, but it's got a lot of info in it and im having trouble finding out exactly what it means.
The error: main.obj:-1: error: LNK2001: unresolved external symbol "public: __thiscall AtpReader::AtpReader(class std::basic_string,class std::allocator >)" (??0AtpReader##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
My code is:
main.cpp:
#include <iostream>
#include "atlasobject.h"
#include "atp.h"
#include "atpreader.h"
using namespace std;
int main()
{
AtpReader reader("E:/doc.txt");
return 0;
}
AtpReader.h:
#ifndef ATPREADER_H
#define ATPREADER_H
#include "atp.h"
class AtpReader
{
public:
AtpReader();
AtpReader(string filename);
void atpReadHeader();
void atpRead();
string decryptLine(string line);
ATP readerATP;
private:
string file;
};
#endif // ATPREADER_H
atp.h:
#ifndef ATP_H
#define ATP_H
#include "atlasobject.h"
#include "vector"
struct Image{
string Dim;
string Vox;
string Ori;
char* data;
};
class ATP
{
public:
ATP();
vector<AtlasObject> listOfMaps;
private:
Image referenceImage;
};
#endif // ATP_H
and AtlasObject.h:
#ifndef ATLASOBJECT_H
#define ATLASOBJECT_H
#include <string>
using namespace std;
class AtlasObject{
public:
//virtual void create();
AtlasObject();
void set_uid(string id);
void set_label(string l);
void set_offset(string o);
void set_mapInfo(string info);
void set_data(char* inData);
void set_isEncrypted(int encrypted);
string get_uid();
string get_label();
string get_offset();
string get_mapInfo();
char* get_data();
int get_isEncrypted();
protected:
string uid;
string label;
string offset;
string mapInfo;
char *data;
int isEncrypted;
};
#endif // ATLASOBJECT_H
my AtpReader.cpp is:
#include "atpreader.h"
#include <iostream>
#include <fstream>
#include <stdint.h>
#include <sstream>
AtpReader::AtpReader()
{
printf("AtpReader()\n");
}
AtpReader::AtpReader(string filename)
{
printf("AtpReader(%s)\n",filename.c_str());
}
I see you did not include AtpReader.h in AtpReader.cpp, but probably you just missed it when you made copy/paste, to insert it here, because if you didn't really include it, the error would have been different. Also, I see you're including in your main.cpp both "atlasobject.h"
and "atp.h" and you don't really need that.
Later edit: Your problem is in the atp.h...you constructor is declared but never defined. Do this: ATP(){};
Try using g++ in linux terminal
make the object files of each of the source codes and then link the object files and run the executable
g++ -c atp.cpp AtpReader.cpp AtlasObject.cpp
g++ -o exe atp.o AtpReader.o AtlasObject.o
./exe
AtpReader.cpp is not getting built or the its object file is not getting linked to final executable. Check if AtpReader.obj/.o is created in build directory.
Because of the linker error you are getting and assuming that this is some of your actual code. Since I can't see any function inlining, global constants or variables being used out of scope I think the problem is located in the AtpReader.cpp, are you missing an #include AtpReader.h there?
With just a function prototype, the compiler can continue without error, but the linker cannot resolve a call to an address because there is no function code or variable space reserved. You will not see this error until you create a call to the function that the linker must resolve.
I am writing a program that needs a pathname to eventually create a global string.
I currently have this pathname hard coded, but would like to use a global variable to replace this.
The problem I am having is that my global variable is undefined. I am also using JNI and the error I am getting is:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f65f981ddd0, pid=11660, tid=140075985102592
#
# JRE version: 7.0_21-b02
# Java VM: OpenJDK 64-Bit Server VM (23.7-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [libstdc++.so.6+0x9ddd0] std::string::size() const+0x0
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/cbil/Desktop/SIGH_Project/July_9/src/hs_err_pid11660.log
#
# If you would like to submit a bug report, please include
# instructions on how to reproduce the bug and visit:
# https://bugs.launchpad.net/ubuntu/+source/openjdk-7/
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
and here is relevant code that is reformatted for simplicity:
file1.cpp
#include <jni.h>
#include "file1.h"
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
const char* myPath;
JNIEXPORT jint JNICALL Java_foo_foo(JNIEnv *env, jobject thisobj, jbyteArray passedPath){
/*Some conversion, don't think it is relevant, but it might be*/
jboolean isCopy;
jbyte* path = env->GetByteArrayElements(passedPath,&isCopy);
int length1 = strlen((const char*)path);
char* convertedVar = (char*)malloc(length1+1);
memcpy(convertedVar,path,length1);
convertedVar[length1] = '\0';
convertedVar = (char*)path;
/*End Conversion*/
globalVariable = convertedVar;
... //Some code to use the variable and releases
}
file2.h (This is where I declare the global variable)
#include <vector>
#include <fstream>
#include <string.h>
extern const char* globalVariable;
extern int someNum;
extern int someLength;
class file2{
public:
static std::vector<std::string> getSomeString(int &someNum, int &someLength);
private:
static const std::vector<std::string> anotherVar;
...//some other variables and methods
}
and finally the code that calls getSomeString
file3.cpp
#include "file2.h"
#include <string.h>
#include <vector>
#include <fstream>
using namespace std;
int someNum = 0;
int someLength = 0;
const char* globalVariable;
vector<string> file2::getSomeString(int &someNum, iint &someLength){
vector<string> data;
ifstream infile(globalVariable); //I think the problem is here
string line;
...// some code that goes through the data file specified by the path name
someNum = data.size();
someLength = data[0].size();
return data;
}
const vector<string> file2::anotherVar = getSomeString(someNum,someLength); //variable that uses the getSomeString method
}
I'll say it here again, I am using JNI. I have gotten errors saying the lib.so file I create has undefined variables, I don't know if this is helpful information.
Any help would be appreciated. Sorry about the long post, I am quite lost.
char* convertedVar = (char*)malloc(length1+1);
memcpy(convertedVar,path,length1);
convertedVar[length1] = '\0';
convertedVar = (char*)path;
I'm pretty sure this last line shouldn't be there. You are going through this malloc/memcpy dance, then promptly drop this allocated-and-initialized block of memory on the floor, and make convertedVar point to something else instead.
Further, I'm pretty sure path pointer will become invalid as soon as the function returns.
extern const char* globalVariable;
This declares the variable, but doesn't define it. You also need to provide a definition, in exactly one source file (not in a header file):
const char* globalVariable;
Curiously, you know enough to do just that with someNum and someLength, but not for globalVariable.
I'm kinda' new to JNI, but been reading alot about JNI when I wanted to use a legacy dll in my project.
Quick enough, I found out that I can't parameters to native methods. Here's an example that I tried to code with no success:
Hello.java:
package HelloWorld;
Public class Hello {
Private static native int HelloWorld();
Private static native int Mirror(int a);
Static {
System.loadLibrary("Example"); //got path in
vm arguments - works.
}
Public static void main(String[] args) {
Int a = 8;
System.out.println(Mirror(a));
}
Used javah to create header which got me this signature:
JNIEXPORT jint JNICALL Java_HelloWorld_Hello_Mirror (JNIEnv *, jclass, jint);
Wrote a cpp:
Same signature as the h with impl of: "return 1";
That's it and... This is the error I get from eclipse:
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloWorld/Hello.Mirror(I)I
at HelloWorld.Hello.main (Hello.java:14)
These are my ideas:
A. Saw something about c and cpp, am I mixing things.
B. jdk or stuff?
C. The library loads perfectly (checked the other function that does not get parameters), maybe the types are incompatible?
Stuck on this for a while, Hope you guys can help me!
Solved!
Just needed to add '{' around both functions in the cpp file, after the "extern c" command...
So i have been looking into JNI calls so i can interact with some pre written C++ programs, i dont know any C++ but am trying to learn some basics. I have just been trying to do a simple call to a method outside my JNI method but always get the following error:
error c3861 'myMethod': identifier not found
#include <stdio.h>
#include <string.h>
#include "StringFuncs.h"
JNIEXPORT jstring JNICALL Java_StringFuncs_changeWord(JNIEnv *env, jobject obj, jstring inStr, jint inLen)
{
const char *inString;
inString = env->GetStringUTFChars(inStr, NULL);
char otherString[40];
strcpy_s(otherString,inString);
if(myMethod())
{
memset(otherString, '-', inLen);
}
jstring newString = env->NewStringUTF((const char*)otherString);
return newString;
}
bool myMethod()
{
return true;
}
int main()
{
return 0;
}
Any words of wisdome?
You have to declare your methods before you call them. So in your header type
bool myMethod();
Or you can move the code above your _changeWord function, then the declaration/definition is in one.
Move myMethod() above Java_StringFuncs_changeWord() in the source file.
In C++ you generally have to declare a symbol before you use it. So, somewhere before Java_StringFuncs_changeWord you need to declare myMethod:
bool myMethod();
If this is going to be a shared function (other cpp modules will call it) then you most likely want to put it in a header file which can be #included by other files. If the function only makes sense to be called by this module, you want to put the declaration at the top of the file, after the other #includes.
You can also declare and define the function in one go by moving the whole function above the function that calls it, but this wont always work (if you have two functions which reference eachother you have to have a separate declaration).