-
August 1st, 2007, 08:08 AM
#1
Problem while calling a method in an .so file
Hi,
I have the following code which attempts to load and call a function from a .so file:
Code:
1) CTEST.h : the same header which is included in the .so
#ifndef CTEST_H_
#define CTEST_H_
#include <iostream>
#include <stdio.h>
using namespace std;
class CTEST {
public:
CTEST ();
virtual ~CTEST();
int* ctest1(int i);
int* ctest2(int i);
private:
int i;
};
typedef CTEST* create_t();
typedef void destroy_t(CTEST*);
#ifdef __cplusplus
extern "C" {
#endif
extern "C" CTEST* create();
extern "C" void destroy(CTEST* p);
#ifdef __cplusplus
}
#endif
#endif /*CTEST_H_*/
2) soprog.cpp: program that loads loadctest.so file and tries to call the method ctest2():
Code:
#include <dlfcn.h>
#include "CTEST.h"
int main(int argc, char **argv)
{
void *lib_handle;
int x = 5;
char *error;
lib_handle = dlopen("/usr/local/lib/libctest.so", RTLD_LAZY);
if (!lib_handle)
{
cout<<dlerror()<<endl;
exit(1);
}
create_t* create_ctest = (create_t*) dlsym(lib_handle, "create");
if ((error = dlerror()) != NULL)
{
cout<<dlerror()<<endl;
exit(1);
}
destroy_t* destroy_ctest = (destroy_t*) dlsym(lib_handle, "destroy");
CTEST* tobj = create_ctest();
int* retval = tobj->ctest2(x);
//cout<<*retval<<endl;
destroy_ctest(tobj);
dlclose(lib_handle);
return 0;
}
The problem I have been facing is the following call gets called:
CTEST* tobj = create_ctest();
As it shows the messages it has in its constructor, thus validating the correct .so loaded and method called.
But whenever I am trying to call the ctest2() method in the following line:
int* retval = tobj->ctest2(x);
The ld is giving the following error message:
soprog.cpp.text+0x200): undefined reference to `CTEST::ctest2(int)'
collect2: ld returned 1 exit status
Can somebody help me in this?
Thanks a lot.
-PD
-
August 1st, 2007, 08:18 AM
#2
Re: Problem while calling a method in an .so file
Have you tried making your member methods virtual?
Btw: I learned it upon this tutorial: http://www.linuxjournal.com/article/3687
-
August 1st, 2007, 08:37 AM
#3
Re: Problem while calling a method in an .so file
Are you sure you remembered to add a definition for that method in your library?
-
August 1st, 2007, 09:11 AM
#4
Re: Problem while calling a method in an .so file
Here follows the simple code which the libctest.so file consists of:
Code:
#include "CTEST.h"
using namespace std;
CTEST::CTEST(){
std::cout<<"CTEST Initialized..."<<std::endl;
}
CTEST::~CTEST(){
std::cout<<"CTEST Deinitialized..."<<std::endl;
}
CTEST* create() {
return new CTEST;
}
void destroy(CTEST* p) {
delete p;
}
int* CTEST::ctest1(int x)
{
this->i = x;
std::cout<<"In CTEST::ctest2(). i is "<<this->i<<std::endl;
return &this->i;
}
int* CTEST::ctest2(int x)
{
this->i = x * x;
std::cout<<"In CTEST::ctest2(). i is "<<this->i<<std::endl;
return &this->i;
}
As you can see the ctest2 method is defined. Also as a proof of my earlier post that the file is loaded please check the output below when I call
CTEST* tobj = create_ctest();
Output:
CTEST Initialized...
CTEST Deinitialized...
The problem occurs only when I try to call the following:
int* retval = tobj->ctest2(x);
Is there anything to do with the Cygwin and g++ I am using?
-Thanks,
PD
-
August 1st, 2007, 10:03 AM
#5
Re: Problem while calling a method in an .so file
As far as the linker knows, there is no implementation for those methods; the implementation in the .so is not known until runtime. Constructors and destructors work because those calls occur within the shared object.
When you created libctest.so, did it create libctest.a as well? If so, linking against that should fix this problem. Otherwise, make CTEST purely interface, and implement it with a subclass in the .so library (and that is only used directly by the .so library).
-
August 1st, 2007, 11:16 AM
#6
Re: Problem while calling a method in an .so file
Originally Posted by Hermit
As far as the linker knows, there is no implementation for those methods; the implementation in the .so is not known until runtime. Constructors and destructors work because those calls occur within the shared object.
When you created libctest.so, did it create libctest.a as well? If so, linking against that should fix this problem. Otherwise, make CTEST purely interface, and implement it with a subclass in the .so library (and that is only used directly by the .so library).
But that's why we used -ldl, isn't it?
Wy I need to create an .a file. I should not bother abt that file since I hav exreated an .so, right?
Not sure what you meant by "CTEST purely interface". Are you saying to make everything pure virtual?
Pease help.
-PD.
-
August 1st, 2007, 11:20 AM
#7
Re: Problem while calling a method in an .so file
What you are doing is creating an interface class and getting a pointer to it via an exported function.
To correctly make this work, you will need to make your destructor and methods that you want to use virtual, otherwise, in a dynamically loaded .SO (works the same for *.DLLs on Windows) you do not know the address of the function. Since the function is not virtual, that means it is not in a VTABLE. However, if it is virtual, a VTABLE will exist in the object, and therefore the address of the function can be found.
Having a PURE VIRTUAL base class, and then hidden sub classes that implement that interface could allow you to have more than 1 definition of the interface you define. That is the basis of 'plugin development'.
-
August 1st, 2007, 12:03 PM
#8
Re: Problem while calling a method in an .so file
Originally Posted by JamesSchumacher
What you are doing is creating an interface class and getting a pointer to it via an exported function.
To correctly make this work, you will need to make your destructor and methods that you want to use virtual, otherwise, in a dynamically loaded .SO (works the same for *.DLLs on Windows) you do not know the address of the function. Since the function is not virtual, that means it is not in a VTABLE. However, if it is virtual, a VTABLE will exist in the object, and therefore the address of the function can be found.
Having a PURE VIRTUAL base class, and then hidden sub classes that implement that interface could allow you to have more than 1 definition of the interface you define. That is the basis of 'plugin development'.
First:
Tried your virtual thing and this is the outcome:
g++ -Wall -L.:/usr/local/lib soprog.cpp -ldl -o soprog
soprog.cpp: In function `int main(int, char**)':
soprog.cpp:29: warning: unused variable 'retval'
/cygdrive/c/DOCUME~1/PRANAB~1/LOCALS~1/Temp/ccTnPw8A.o:soprog.cpp.text+0x200): undefined reference to `CTEST::ctest2(int)'
collect2: ld returned 1 exit status
make: *** [soprog] Error 1
make: Target `all' not remade because of errors.
Thanks,
PD
-
August 1st, 2007, 04:42 PM
#9
Re: Problem while calling a method in an .so file
Code:
class CTEST
{
public:
CTEST ();
virtual ~CTEST();
virtual int* ctest1(int i);
virtual int* ctest2(int i);
private:
int i;
};
Also check your compiler options, are they both being compiler with the same compiler, etc. You may need -fPIC for your library.
-
August 1st, 2007, 10:31 PM
#10
Re: Problem while calling a method in an .so file
Hi Everbody,
Thanks for the explanations and it indeed worked when the method entrires are in vtable.
Thanks again.
-PD.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|