Question

I just started coding a gtalk chat bot using libjingle. I'm having a problem getting the compiler to find the XmppClient class called by XmppPump class. The XmppClient is provided by libjingle in the talk/xmpp/xmppclient.h file, but for some reason it's not working for me and it has been frustrating me lately. Hopefully you guys will be able to help me out!

I'm using libjingle-0.5.1 and my g++ compiler version is 4.4.5. My OS is Ubuntu 10.10, 32-bit.

Here's how I'm trying to compile my code:

g++ -g -Werror -DPOSIX -DEXPAT_RELATIVE_PATH -DFEATURE_ENABLE_SSL -DHAVE_OPENSSL_SSL_H=1 -I../include -I../misc/libjingle-0.5.1 -I../misc/libjingle-0.5.1/talk/third_party/expat-2.0.1 -I../misc/libjingle-0.5.1/talk/third_party/srtp/include -L../lib -lpthread -lssl -o ../bin/gtalk_bot.bin ../obj/main.o /usr/local/lib/libglog.a ../misc/libjingle-0.5.1/talk/build/dbg/lib/libjingle.a ../misc/libjingle-0.5.1/talk/build/dbg/lib/libexpat.a ../misc/libjingle-0.5.1/talk/build/dbg/lib/libsrtp.a ../misc/libjingle-0.5.1/talk/build/dbg/lib/libxmpphelp.a

Here's the error message:

../misc/libjingle-0.5.1/talk/build/dbg/lib/libxmpphelp.a(xmpppump.o): In function `XmppPump::XmppPump(XmppPumpNotify*)':
xmpppump.cc:(.text._ZN8XmppPumpC2EP14XmppPumpNotify+0x6e): undefined reference to `buzz::XmppClient::XmppClient(talk_base::TaskParent*)'
../misc/libjingle-0.5.1/talk/build/dbg/lib/libxmpphelp.a(xmpppump.o): In function `XmppPump::XmppPump(XmppPumpNotify*)':
xmpppump.cc:(.text._ZN8XmppPumpC1EP14XmppPumpNotify+0x6e): undefined reference to `buzz::XmppClient::XmppClient(talk_base::TaskParent*)'
../misc/libjingle-0.5.1/talk/build/dbg/lib/libxmpphelp.a(xmpppump.o): In function `XmppPump::DoLogin(buzz::XmppClientSettings const&, buzz::AsyncSocket*, buzz::PreXmppAuth*)':
xmpppump.cc:(.text._ZN8XmppPump7DoLoginERKN4buzz18XmppClientSettingsEPNS0_11AsyncSocketEPNS0_11PreXmppAuthE+0xa9): undefined reference to `buzz::XmppClient::Connect(buzz::XmppClientSettings const&, std::basic_string, std::allocator > const&, buzz::AsyncSocket*, buzz::PreXmppAuth*)'
../misc/libjingle-0.5.1/talk/build/dbg/lib/libxmpphelp.a(xmpppump.o): In function `XmppPump::DoDisconnect()':
xmpppump.cc:(.text._ZN8XmppPump12DoDisconnectEv+0x25): undefined reference to `buzz::XmppClient::Disconnect()'
../misc/libjingle-0.5.1/talk/build/dbg/lib/libxmpphelp.a(xmpppump.o): In function `XmppPump::SendStanza(buzz::XmlElement const*)':
xmpppump.cc:(.text._ZN8XmppPump10SendStanzaEPKN4buzz10XmlElementE+0x2c): undefined reference to `buzz::XmppClient::SendStanza(buzz::XmlElement const*)'
collect2: ld returned 1 exit status
make: *** [../bin/gtalk_bot.bin] Error 1

And here's my code:

#include <string>
#include <iostream>
#include <assert.h>
#include <getopt.h>
#include "glog/logging.h"
#include "talk/base/thread.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/socketaddress.h"
#include "talk/base/cryptstring.h"
#include "talk/base/ssladapter.h"
#include "talk/xmpp/jid.h"
#include "talk/xmpp/xmppclient.h"
#include "talk/xmpp/xmppclientsettings.h"
#include "talk/examples/login/xmpppump.h"
#include "talk/examples/login/xmppauth.h"
#include "talk/examples/login/xmppthread.h"

using namespace std;

int readCommandLineArguments(int argc, char **argv);
int getUserName(string *username);
int getPassword(string *password);

buzz::Jid serverJid;
string username;
string password;
string auth_cookie;


int main(int argc, char **argv){
 int status = 0;

 // use: GLOG_log_dir="log" ./gtalk_bot.bin
 google::InitGoogleLogging(argv[0]);

 talk_base::PhysicalSocketServer pss;
 talk_base::AutoThread main_thread(&pss);

 // Get the information we'll need to sign in
 buzz::Jid jid;
 talk_base::InsecureCryptStringImpl pass;
 buzz::XmppClientSettings xcs;
 XmppPump pump;
 //XmppHandler xhandler;

 status = readCommandLineArguments(argc, argv);

 if(username.empty()){
  // get the user name if there's none in the command line argument
  status = getUserName(&username);
 }
 jid = buzz::Jid(username);
 assert(jid.IsValid() || jid.node() != "");

 if(!username.empty() && password.empty()){
  // If username is provided, but the password isn't, ask for one.
  status = getPassword(&password);
 }
 pass.password() = password;

 // Turn on SSL
 talk_base::InitializeSSL();

 xcs.set_user(jid.node());
 xcs.set_resource("one_chat_bot"); //TODO: need to investigate what this is
 xcs.set_host(jid.domain());
 xcs.set_use_tls(true);
 xcs.set_pass(talk_base::CryptString(pass));
 xcs.set_server(talk_base::SocketAddress("talk.google.com", 5222));

 //xhandler.DoLogin(xcs, new XmppSocket(true), NULL);
// xhandler.DoLogin(xcs, new XmppSocket(true), NULL);
 main_thread.Run();
// xhandler.DoDisconnect();

 //delete objects here

 return 0;
}



int readCommandLineArguments(int argc, char **argv){
 int input = 0;
 int rc = 0;
 int options_index = 0;

 static struct option long_options[] = {
  {"username", required_argument, 0, 'u'},
  {"password", required_argument, 0, 'p'},
  {0, 0, 0, 0}
 };

 while((input = getopt_long(argc, argv, "u:p:", long_options, &options_index)) != -1 && rc == 0){
  switch(input){
   case 'u':
    if(optarg){
     username = optarg;
    }
    break;
   case 'p':
    if(optarg){
     password = optarg;
    }
    break;
   case '?':
   default:
    rc = 1;
    break;
  }
 }

 return rc;
}



int getUserName(string *username){
 int rc = 0;

 cout << "google username: ";
 cin >> *username;

 return rc;
}


int getPassword(string *password){
 int rc = 0;

 cout << "password: ";
 cin >> *password;

 return rc;
}

Here's my directory structure. There are three libjingle folders because I was experimenting and trying different things to see if I can resolve the compilation problem. The libjingle folders are unchanged except that expat-2.0.1/ and srtp/ folders are copied to the libjingle/talk/third_party/ folder. The libjingle-0.5.1/ directory structure is pretty much the same as the svn trunk located here:

http://code.google.com/p/libjingle/source/browse/trunk/#trunk

Except that my libjingle-0.5.1 folder is already compiled.

gtalk_bot$ ls *
bin:
log

include:

lib:

misc:
expat-2.0.1         glog-0.3.1.tar.gz  libjingle-0.4.0.tar.gz  libjingle-0.5.1      libjingle-0.5.tar.gz  srtp            swtoolkit
expat-2.0.1.tar.gz  libjingle-0.4.0    libjingle-0.5           libjingle-0.5.1.zip  scons-2.0.1.tar.gz    srtp-1.4.4.tgz  swtoolkit.0.9.1.zip

obj:
main.o  XmppHandler.o

src:
main.cc  main.o  Makefile  SConstruct  XmppHandler.cc  XmppHandler.h  XmppSocket.cc  XmppSocket.h

test:

Here's the libjingle's build directory:

gtalk_bot/misc/libjingle-0.5.1/talk/build/dbg$ ls *
lib:
libexpat.a  libjingle.a  libsrtp.a  libxmpphelp.a

obj:
base  call  examples  libexpat.a  libjingle.a  libsrtp.a  libxmpphelp.a  login  p2p  relayserver  session  stunserver  third_party  xmllite  xmpp

staging:
call  login  relayserver  stunserver
Was it helpful?

Solution

Many thanks to the libjingle team for solving my problem. Apparently, the static library ordering is important. I just had to re-order the libraries to:

libxmpphelp.a  libjingle.a libexpat.a libsrtp.a

See "man ld":

The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again.

Now, I'm able to compile my app. Hope someone else will find this useful.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top