I am trying to create a dynamic(.so) wrapper library along mongoDB c++ driver. There is no problem with the compilation but when I test it in a C++ sample program i get the error
undefined symbol: _ZN5mongo18DBClientConnection15_numConne
which i assume has something to do with name mangling issues.
I compiled the library as
g++ -fPIC -shared mongoquery.cpp -I/pathto/mongodriver -lmongoclient -lboost_thread-mt -lboost_filesystem -lboost_program_options -o libmongoquery.so
Here's the program I am using for testing:
#include <iostream>
#include <dlfcn.h>
#include "mongoquery.hpp"
using namespace std;
int main()
{
void *lib_handle;
int (*fn)(int *,string);
lib_handle=dlopen("./libmongoquery.so",RTLD_NOW);
if(!lib_handle)
{
cerr<<"Error"<<dlerror();
return 1;
}
fn=(int (*)(int *,string))dlsym(lib_handle,"count_query");
string q="{}";
int n;
(*fn)(&n,q);
cout<<n;
dlclose(lib_handle);
return 0;
}
the header mongoquery.hpp contains
#include <iostream>
#include <client/dbclient.h>
#define HOST "localhost"
#define COLLECTION "test.rules"
using namespace mongo;
using namespace std;
class mongoquery
{
private:
string q;
mongo::DBClientConnection c;
public:
mongoquery(string);
int result_count();
};
int count_query(int *,string);
Thanks
The answer can be followed from this question
Dynamic library uses statics libraries, undefined symbols appears
Added for achival purpose
Related
I am trying to declare two classes C1 and C2 in files nstest1.h and nstest2.h which are defined in files nstest1.cpp and nstest2.cpp respectively. Both the classes are defined under same namespace.
Following are the files :
//nstest1.h
namespace Mine{
class C1{
public:
void callme();
};
}
//nstest2.h
namespace Mine {
class C2 {
public:
void callme();
};
}
//nstest1.cpp
#include<iostream>
#include "nstest1.h"
using namespace std;
using namespace Mine;
void Mine::C1::callme(){
std::cout << "Please call me " << std::endl;
}
//nstest2.cpp
#include<iostream>
#include "nstest2.h"
using namespace std;
using namespace Mine;
void Mine::C2::callme(){
std::cout << "Please call me too" << std::endl ;
}
Following file tries to use this classes using namespace Mine.
//nstest.cpp
#include<iostream>
#include "nstest1.h"
#include "nstest2.h"
using namespace std;
using namespace Mine;
int main(){
Mine::C1 c1;
Mine::C2 c2;
c1.callme();
c2.callme();
return 0;
}
When I compile using command "g++ nstest.cpp", I get following error :
/tmp/cc2y4zc6.o: In function `main':
nstest.cpp:(.text+0x10): undefined reference to `Mine::C1::callme()'
nstest.cpp:(.text+0x1c): undefined reference to `Mine::C2::callme()'
collect2: error: ld returned 1 exit status
If the definitions are moved to the declaration files (nstest1.h and nstest2.h), it works fine. Not sure whats happening here. Am I missing something ?
Thanks in advance :) .
You need to include the other .cpp files when building the program.
Option 1: Compile all the files and build the executable in one command
g++ nstest.cpp nstest1.cpp nstest2.cpp -o nstest
Option 2: Compile each file separately and then build the executable after that
g++ -c nstext1.cpp
g++ -c nstest2.cpp
g++ -c nstest.cpp
g++ nstest.o nstest1.o nstext2.o -o nstest
Your problem happens at link time. Your headers are fine. But you should compile the other cpp files aswell.
In armadillo c++ i use some api and using oracle occi try to insert the value into oracle table,but I get some error like this:-
/home/oracle/Desktop/project/armadillo-4.450.4/include/armadillo_bits/typedef_elem.hpp:79: error: typedef arma::s32 arma::sword
/usr/include/oracle/11.1/client/ociap.h:10830: error: reference to ‘sword’ is ambiguous
/usr/include/oracle/11.1/client/oratypes.h:227: error: candidates are: typedef int sword
My sample code is:-
main.cpp
#include <stdio.h>
#include <iostream>
#include "db_manager.h"
#include <armadillo>
using namespace arma;
int glbsize;//this variable is global it is declared in global_variables.h
mat glbmtrx;//this variable is global it is declared in global_variables.h
void add()
{
double deter;
int ppp=0;
mat z;
mat x = randu<mat>(4,4);
mat y = randu<mat>(4,4);
z=x+y;
mystruct strct;
strct.mymatrix=z;//variable from comm.structure
glbmtrx=strct.mymatrix;//varible from glb.variables
deter= det(z);
db_manager db;
db.load_determinant(deter);
}
int main()
{
add();
return 0;
}
db_manager.cpp
#include "db_manager.h"
#include <sstream>
#include <iostream>
#include <sstream>
#include <fstream>
using namespace oracle::occi;
using namespace std;
Environment *env;
Connection *con;
void db_manager::load_determinant(double det)
{
mystruct strct;
strct.deter_size=det;//var from comm.structure
string user = "user";
string passwd = "p#$$word";
string db = "localhost:1521/sisdba";
env = Environment::createEnvironment((Environment::Mode)(Environment::OBJECT|Environment::THREADED_MUTEXED));
con = env->createConnection(user, passwd, db);
Statement *stmt = NULL;
ResultSet *rs = NULL;
string concat1="";
concat1=static_cast<ostringstream*>(&(ostringstream()<<det))->str();
string sql="insert into determinanit_table values('"+concat1+"')";
stmt = con->createStatement(sql);
stmt->executeUpdate(sql);
env->terminateConnection (con);
Environment::terminateEnvironment (env);
}
db_manager.h
#include "includes/global_variables.h"
#include <occi.h>
class db_manager
{
public:
db_manager(void);
~db_manager(void);
void load_determinant(double det);
};
common_struct.h
#include <armadillo>
using namespace arma;
using namespace std;
struct mystruct
{
mat mymatrix;
double deter_size;
};
global_variable.h
#include "../includes/common_structures.h"
using namespace arma;
extern int glbsize;
extern mat glbmtrx;
Makefile:
excute:main.o db_manager.o
g++ -o excute main.o db_manager.o \
-I/home/oracle/Desktop/sum_result/armadillo-4.450.4/include -DARMA_USE_BLAS -DARMA_USE_LAPACK -DARMA_DONT_USE_WRAPPER -lblas -llapack \
-I/usr/include/oracle/11.1/client \
-L$(ORACLE_HOME)/lib -lclntsh -locci
%.o: %.cpp
g++ -c -o $# $< -ggdb \
-I/home/oracle/Desktop/sum_result/armadillo-4.450.4/include -DARMA_USE_BLAS -DARMA_USE_LAPACK -DARMA_DONT_USE_WRAPPER -lblas -llapack \
-I/usr/include/oracle/11.1/client \
-L$(ORACLE_HOME)/lib -lclntsh -locci
clean:
rm *.o excute
Some comments on your code :
Be carreful with global variables (mat glbmtrx; in main.cpp). If the library armadillo also use global variables to work, you have no guaranty about the order of allocation of all the global variables. If your variable glbmtrx is allocated before a global variable used by the constructor of mat, you are going to have a problem ! If you really need that, prefer to use the Singleton Pattern.
In common_struct.h : never call using in a header file ! You can create conflict between namespaces. Imagine, I want to merge your application and my application. If I use a class named vector in my application, it will be complex to call it without conflicts, due to the fact that vector refers to std::vector due to your file.
Actually, it's possible your problem comes from a conflict of namespaces. I advise you to never call using namespace std and always add it to the classes/functions you call. When I use several libraries together, I never call using namespace xxx and I always use global names.
I m trying to compile this code and linking fails with the following error:
this is how i m compiling it;
g++ logtester.cc -I/home/foo/include -L/home/foo/lib -llog4cxx
/tmp/ccADKreY.o(.text+0x120): In function `main': undefined reference to `FrameworkLogger::getInstance()'
collect2: ld returned 1 exit status
Why? how can i fix it?
#include <log4cxx/logger.h>
#include <log4cxx/xml/domconfigurator.h>
using namespace log4cxx;
using namespace log4cxx::xml;
using namespace log4cxx::helpers;
class FrameworkLogger
{
private:
FrameworkLogger();
LoggerPtr logger;
public:
static LoggerPtr getInstance();
};
(Another file:)
#include "FrameworkLogger.h"
#include <iostream>
LoggerPtr FrameworkLogger::getInstance()
{
std::cout<<"test";
}
(Yet another file:)
#include "FrameworkLogger.h"
#include <iostream>
using namespace std;
int main(){
// LoggerPtr logger =
FrameworkLogger::getInstance();
std::cout<<"test";
}
This sounds like a linker error. Ensure that you are properly linking all of your object files
You need to list all compilation units (.cc files) in the compiler invocation:
g++ logtester.cc the-file-you-have-not-named.cc -I/home/foo/include -L/home/foo/lib -llog4cxx
I'm on Linux, the question is concerning shared objects of C++ classes.
The problem comes when my shared objects try to use resources linked into the main executable. I have the following codes:
loader.cpp:
#include <dlfcn.h>
#include <iostream>
#include "CommonInfo.h"
using namespace std;
int main(int argc, char** argv) {
for(int i=1; i<argc; ++i) {
string pth = "./";
pth.append(argv[i]);
void* dh = dlopen(pth.c_str(), RTLD_NOW);
if(dh==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo::GetInfoFunc getInfo = (CommonInfo::GetInfoFunc)(dlsym(dh,"getInfo"));
if(getInfo==NULL) {
cerr << dlerror() << endl;
return 1;
}
CommonInfo* info = getInfo();
cout << "INFO: " << info->getX() << endl;
delete info;
}
return 0;
}
CommonInfo.h:
#include <string>
class CommonInfo {
public:
typedef CommonInfo* (*GetInfoFunc)();
private:
std::string x;
public:
CommonInfo(const std::string& nx);
std::string getX() const;
};
EDIT:
I accidentaly forgot to ctrl-c + ctrl-v the source of CommonInfo.cpp here. Of course, it is there during compilation, so CommonInfo.cpp:
#include "CommonInfo.h"
CommonInfo::CommonInfo(const std::string& nx) : x(nx) {
}
std::string CommonInfo::getX() const {
return x;
}
A Plugin.h header:
#include "CommonInfo.h"
extern "C" CommonInfo* getInfo();
A very simple Plugin.cpp:
#include <iostream>
#include "Plugin.h"
#include "CommonInfo.h"
using namespace std;
CommonInfo* getInfo() {
return new CommonInfo("I'm a cat!");
}
Compiling is done with:
g++ -rdynamic -ldl -Werror CommonInfo.cpp loader.cpp -o loader
g++ -shared -fPIC -Werror Plugin.cpp -o Plugin.so
Running:
./loader Plugin.so
And there goes the error:
./loader: symbol lookup error: ./Plugin.so: undefined symbol: _ZN10CommonInfoC1ERKSs
Indeed, looking inside Plugin.so with nm Plugin.so | grep -i CommonInfo it gives an 'U' for this symbol (unresolved), which is perfectly ok.
Also, looking inside the binary of loader with nm loader.so | grep -i CommonInfo I could find the symbol with 'T', which is also ok.
Question is, shouldn't dlfcn.h unresolve the symbol in question from the main binary? Without this feature it becomes quite hard to use these stuff... Do I have to write a class factory function for CommonInfo, load it with dlfcn from the plugin and call that?
Thanks in advance,
Dennis
I haven't looked closely at your code, but I have in the past found behavior like you describe in the title when I did not link the executable with -E. (Or -Wl,-E when linking with gcc rather than ld.)
Note that not all platforms let the shared libraries take symbols from the calling binary. Linux and the *BSDs allow you to. But if you ever want to port to, say, Windows, you will not be able to use this pattern. I believe there are also some Unix-type OS's that won't let you do this. (It's been a while so I don't remember... Maybe it was Solaris?)
I am working in c++ /ubuntu.
I have:
libr.hpp
#ifndef LIBR
#define LIBR
#include <string>
using namespace std;
class name
{
public:
name();
~name();
std::string my_name;
std::string method (std::string s);
};
#endif
and
libr.cpp
#include <iostream>
#include <string>
#include <stdlib.h>
#include "libr.hpp"
using namespace std;
name::name()
{
}
std::string name::method(std::string s)
{
return ("YOUR NAME IS: "+s);
}
From these two I've created a libr.a.
In test.cpp:
#include <iostream>
#include <string>
#include <stdlib.h>
#include "libr.hpp"
using namespace std;
int main()
{
name *n = new name();
n->my_name="jack";
cout<<n->method(n->my_name)<<endl;
return 0;
}
I compile with g++ and libr.a. I have an error: "name::name() undefined reference", why?
I would like to mention that I've added in qt creator at qmake the .a. When I compile, I have the error. How can I solve it?
This is a linker error, not a compiler error. It means that you have called but you have not defined the constructor. Your allocation name *n = new name(); calls the constructor.
Since you defined the constructor in your libr.cpp, what this means is that this compilation unit is not making its way into your executable. You mentioned that you are compiling with libr.a. When you compile your libr.cpp the result is a .o file, not a .a file.
You are not linking libr.o into your executable.
What are the steps you're using to compile your "project"?
I performed the following steps and managed to build it with warnings/errors.
g++ -Wall -c libr.cpp
ar -cvq libr.a libr.o
g++ -Wall -o libr main.cpp libr.a
One last thing, if I change the order off the last command, like
g++ -Wall -o libr libr.a main.cpp
I get the following error:
Undefined first referenced
symbol in file
name::name() /tmp/cc4Ro1ZM.o
name::method(std::basic_string<char, std::char_traits<char>, std::allocator<char
> >)/tmp/cc4Ro1ZM.o
ld: fatal: Symbol referencing errors. No output written to libr
collect2: ld returned 1 exit status
in fact , you needn't define the destructor yourself because the default destructor will be used when the class calling is over.
and in the VS2008,it's all right!