LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-12-2016, 09:26 AM   #1
trist007
Senior Member
 
Registered: May 2008
Distribution: Slackware
Posts: 1,052

Rep: Reputation: 70
undefined reference to a prototype included in a header...


Hello,

I am trying to see why g++ is giving me this error.
Code:
rgonzale@darkstar:~1060 g++ main.cpp -luici
main.cpp: In function ‘int login()’:
main.cpp:17: warning: deprecated conversion from string constant to ‘char*’
/tmp/cchB0XrG.o: In function `login()':
main.cpp:(.text+0x24): undefined reference to `u_connect(unsigned short, char*)'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/libuici.so: undefined reference to `addr2name'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/libuici.so: undefined reference to `name2addr'
collect2: ld returned 1 exit status
I have two header files

uici.h
Code:
#define UPORT
typedef unsigned short u_port_t;
int u_open(u_port_t port);
int u_accept(int fd, char *hostn, int hostnsize);
int u_connect(u_port_t port, char *hostn);
uiciname.h
Code:
#include <netinet/in.h>
#define REENTRANT_NONE 0
#define REENTRANT_R 1
#define REENTRANT_MUTEX 2
#define REENTRANT_POSIX 3

int name2addr(char *name, in_addr_t *addrp);
void addr2name(struct in_addr addr, char *name, int namelen);
Then main.cpp
Code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <string>
#include "uici.h"
#include "uiciname.h"

using namespace std;

int login() {

  long long number;
  u_port_t port;
  pid_t child;
  int requestfd, result, n;
	char *hostname = "127.0.0.1";

	port = 25;

  if((requestfd = u_connect(port, hostname)) == -1)  {
    perror("Failed to make connection");
    return 1;
  }
  write(requestfd, &number, sizeof(long long));
  read(requestfd, &result, sizeof(int));
  fprintf(stderr, "%i\n", result);

	return 0;

}

void runCommand(string input)
{
	if(input.compare("open mail server") == 0)
	{
		cout << "> connecting...";
		login();
		cout << "> connection established";
	}

	if(input.compare("close") == 0)
		exit(0);
	if(input.compare("quit") == 0)
		exit(0);
	if(input.compare("q") == 0)
		exit(0);
}

int main() {

	char c;
	string input;

	do {
			cout << "> ";
			getline(cin, input);

			runCommand(input);

			} while ( cin.good() );

	return 0;
}
I am using a shared library libuici.so

I compiled uici.c into a shared library libuici.so and put it in /usr/lib64
uici.c
Code:
/* uici.c  sockets implementation */

#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include "uici.h"
#include "uiciname.h"

#ifndef MAXBACKLOG
#define MAXBACKLOG 50
#endif

/*
 *                           u_igniore_sigpipe
 * Ignore SIGPIPE if the default action is in effect.
 *
 * returns: 0 if successful
 *          -1 on error and sets errno
 */
static int u_ignore_sigpipe() {
   struct sigaction act;

   if (sigaction(SIGPIPE, (struct sigaction *)NULL, &act) == -1)
      return -1;
   if (act.sa_handler == SIG_DFL) {
      act.sa_handler = SIG_IGN;
      if (sigaction(SIGPIPE, &act, (struct sigaction *)NULL) == -1)
         return -1;
   }
   return 0;
}

/*
 *                           u_open
 * Return a file descriptor, which is bound to the given port.
 *
 * parameter:
 *        s = number of port to bind to
 * returns:  file descriptor if successful
 *           -1 on error and sets errno
 */
int u_open(u_port_t port) {
   int error;
   struct sockaddr_in server;
   int sock;
   int true = 1;

   if ((u_ignore_sigpipe() == -1) ||
        ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
      return -1;

   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&true,
                  sizeof(true)) == -1) {
      error = errno;
      while ((close(sock) == -1) && (errno == EINTR));
      errno = error;
      return -1;
   }

   server.sin_family = AF_INET;
   server.sin_addr.s_addr = htonl(INADDR_ANY);
   server.sin_port = htons((short)port);
   if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) ||
        (listen(sock, MAXBACKLOG) == -1)) {
      error = errno;
      while ((close(sock) == -1) && (errno == EINTR));
      errno = error;
      return -1;
   }
   return sock;
}

/*
 *                           u_accept
 * Wait for a connection request from a host on a specified port.
 *
 * parameters:
 *      fd = file descriptor previously bound to listening port
 *      hostn = a buffer that will hold the name of the remote host
 *      hostnsize = size of hostn buffer
 * returns:  a communication file descriptor on success
 *              hostn is filled with the name of the remote host.
 *           -1 on error with errno set
 *
 * comments: This function is used by the server to wait for a
 * communication.  It blocks until a remote request is received
 * from the port bound to the given file descriptor.
 * hostn is filled with an ASCII string containing the remote
 * host name.  It must point to a buffer of size at least hostnsize.
 * If the name does not fit, as much of the name as is possible is put
 * into the buffer.
 * If hostn is NULL or hostnsize <= 0, no hostname is copied.
 */
int u_accept(int fd, char *hostn, int hostnsize) {
   int len = sizeof(struct sockaddr);
   struct sockaddr_in netclient;
   int retval;

   while (((retval =
           accept(fd, (struct sockaddr *)(&netclient), &len)) == -1) &&
          (errno == EINTR))
      ;
   if ((retval == -1) || (hostn == NULL) || (hostnsize <= 0))
      return retval;
   addr2name(netclient.sin_addr, hostn, hostnsize);
   return retval;
}

/*
 *                           u_connect
 * Initiate communication with a remote server.
 *
 * parameters:
 *     port  = well-known port on remote server
 *     hostn = character string giving the Internet name of remote host
 * returns:  a communication file descriptor if successful
 *           -1 on error with errno set
 */
int u_connect(u_port_t port, char *hostn) {
   int error;
   int retval;
   struct sockaddr_in server;
   int sock;
   fd_set sockset;

   if (name2addr(hostn,&(server.sin_addr.s_addr)) == -1) {
      errno = EINVAL;
      return -1;
   }
   server.sin_port = htons((short)port);
   server.sin_family = AF_INET;

   if ((u_ignore_sigpipe() == -1) ||
        ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
      return -1;

   if (((retval =
       connect(sock, (struct sockaddr *)&server, sizeof(server))) == -1) &&
       ((errno == EINTR) || (errno == EALREADY))) {
       FD_ZERO(&sockset);
       FD_SET(sock, &sockset);
       while ( ((retval = select(sock+1, NULL, &sockset, NULL, NULL)) == -1) &&
               (errno == EINTR) ) {
          FD_ZERO(&sockset);
          FD_SET(sock, &sockset);
       }
   }
   if (retval == -1) {
        error = errno;
        while ((close(sock) == -1) && (errno == EINTR));
        errno = error;
        return -1;
   }
   return sock;
}
I compiled with
Code:
gcc -c fpic uici.c
gcc -shared -o libuici.so uici.o
cp libuici.so /usr/lib64

rgonzale@darkstar:~1063 sudo ldconfig -vv | grep uici
ldconfig: /etc/ld.so.conf.d/kernel-2.6.32-431.5.1.el6.x86_64.conf:6: duplicate hwcap 1 nosegneg
ldconfig: /etc/ld.so.conf.d/kernel-2.6.32-504.8.1.el6.x86_64.conf:6: duplicate hwcap 1 nosegneg
ldconfig: Path `/usr/lib64/mysql' given more than once
	libuici.so -> libuici.so
Now I am trying to compile main.cpp
Code:
g++ main.cpp -luici
rgonzale@darkstar:~1060 g++ main.cpp -luici
main.cpp: In function ‘int login()’:
main.cpp:17: warning: deprecated conversion from string constant to ‘char*’
/tmp/cchB0XrG.o: In function `login()':
main.cpp:(.text+0x24): undefined reference to `u_connect(unsigned short, char*)'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/libuici.so: undefined reference to `addr2name'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/libuici.so: undefined reference to `name2addr'
collect2: ld returned 1 exit status
The header files that I include have the prototypes for u_connect, addr2name, and name2addr.

I am using CentOS 6.8 on a 64 bit server. I understand that I am using a C shared library and headers with a C++ program. I heard you can do this so that is why I am trying. I don't want to use boost. Thank you.

Also, I could put the header files(uici.h and uiciname.h) into /usr/include then change them to "uici.h" "uiciname.h" to <uici.h> and <uiciname.h> correct?

-Tristan

Last edited by trist007; 06-12-2016 at 09:32 AM.
 
Old 06-12-2016, 09:54 AM   #2
hazel
LQ Guru
 
Registered: Mar 2016
Location: Harrow, UK
Distribution: LFS, AntiX, Slackware
Posts: 7,574
Blog Entries: 19

Rep: Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452Reputation: 4452
Where is the actual code for the addr2name and name2addr functions? It should be in your library but I can't see it there. Your error comes from ld and not from gcc, so it is the code for these functions that is not being found; the definitions in the headers have been read successfully.
 
Old 06-12-2016, 10:11 AM   #3
trist007
Senior Member
 
Registered: May 2008
Distribution: Slackware
Posts: 1,052

Original Poster
Rep: Reputation: 70
Ah yes good catch, ok now I have a uiciname.c

Code:
/* uiciname.c  name resolution functions */

#include <ctype.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "uiciname.h"

#ifndef REENTRANCY
#define REENTRANCY REENTRANT_NONE
#endif

#if REENTRANCY==REENTRANT_MUTEX
#include <pthread.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

#if REENTRANCY==REENTRANT_NONE
/* Convert struct in_addr to a host name */
void addr2name(struct in_addr addr, char *name, int namelen) {
   struct hostent *hostptr;
   hostptr = gethostbyaddr((char *)&addr, 4, AF_INET);
   if (hostptr == NULL)
      strncpy(name, inet_ntoa(addr), namelen-1);
   else
      strncpy(name, hostptr->h_name, namelen-1);
   name[namelen-1] = 0;
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   struct hostent *hp;

   if (isdigit((int)(*name)))
      *addrp = inet_addr(name);
   else {
      hp = gethostbyname(name);
      if (hp == NULL)
         return -1;
      memcpy((char *)addrp, hp->h_addr_list[0], hp->h_length);
   }
   return 0;
}
#elif REENTRANCY==REENTRANT_R
#define GETHOST_BUFSIZE 8192
void addr2name(struct in_addr addr, char *name, int namelen) {
   char buf[GETHOST_BUFSIZE];
   int h_error;
   struct hostent *hp;
   struct hostent result;

   hp = gethostbyaddr_r((char *)&addr, 4, AF_INET, &result, buf,
                         GETHOST_BUFSIZE, &h_error);
   if (hp == NULL)
      strncpy(name, inet_ntoa(addr), namelen-1);
   else
      strncpy(name, hp->h_name, namelen-1);
   name[namelen-1] = 0;
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   char buf[GETHOST_BUFSIZE];
   int h_error;
   struct hostent *hp;
   struct hostent result;

   if (isdigit((int)(*name)))
      *addrp = inet_addr(name);
   else {
      hp = gethostbyname_r(name, &result, buf, GETHOST_BUFSIZE, &h_error);
      if (hp == NULL)
         return -1;
      memcpy((char *)addrp, hp->h_addr_list[0], hp->h_length);
   }
   return 0;
}
#elif REENTRANCY==REENTRANT_MUTEX
/* Convert struct in_addr to a host name */
void addr2name(struct in_addr addr, char *name, int namelen) {
   struct hostent *hostptr;

   if (pthread_mutex_lock(&mutex) == -1) {
      strncpy(name, inet_ntoa(addr), namelen-1);
      name[namelen-1] = 0;
      return;
   }
   hostptr = gethostbyaddr((char *)&addr, 4, AF_INET);
   if (hostptr == NULL)
      strncpy(name, inet_ntoa(addr), namelen-1);
   else
      strncpy(name, hostptr->h_name, namelen-1);
   pthread_mutex_unlock(&mutex);
   name[namelen-1] = 0;
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   struct hostent *hp;

   if (isdigit((int)(*name)))
      *addrp = inet_addr(name);
   else {
      if (pthread_mutex_lock(&mutex) == -1)
         return -1;
      hp = gethostbyname(name);
      if (hp == NULL) {
         pthread_mutex_unlock(&mutex);
         return -1;
      }
      memcpy((char *)addrp, hp->h_addr_list[0], hp->h_length);
      pthread_mutex_unlock(&mutex);
   }
   return 0;
}
#elif REENTRANCY==REENTRANT_POSIX
/* Convert struct in_addr to a host name */
void addr2name(struct in_addr addr, char *name, int namelen) {
   struct sockaddr_in saddr;
   saddr.sin_family = AF_INET;
   saddr.sin_port = 0;
   saddr.sin_addr = addr;
   if (getnameinfo((struct sockaddr *)&saddr, sizeof(saddr), name, namelen,
         NULL, 0, 0) != 0) {
      strncpy(name, inet_ntoa(addr), namelen-1);
      name[namelen-1] = 0;
   }
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   struct addrinfo hints;
   struct addrinfo *res;
   struct sockaddr_in *saddrp;

   hints.ai_flags = AI_PASSIVE;
   hints.ai_family = PF_INET;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = 0;
   hints.ai_addrlen = 0;
   hints.ai_canonname = NULL;
   hints.ai_addr = NULL;
   hints.ai_next = NULL;

   if (getaddrinfo(name, NULL, &hints, &res) != 0)
      return -1;
   saddrp = (struct sockaddr_in *)(res->ai_addr);
   memcpy(addrp, &saddrp->sin_addr.s_addr, 4);
   freeaddrinfo(res);
   return 0;
}

#endif
which I compiled into a shared lib and put into /usr/lib64

Code:
rgonzale@darkstar:~1088 g++ main.cpp -luici -luiciname
main.cpp: In function ‘int login()’:
main.cpp:17: warning: deprecated conversion from string constant to ‘char*’
/tmp/cc2Iv0nF.o: In function `login()':
main.cpp:(.text+0x24): undefined reference to `u_connect(unsigned short, char*)'
collect2: ld returned 1 exit status
 
Old 06-12-2016, 10:27 AM   #4
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,863
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
ad1:
Code:
old: char *variable= "value";
new: const char *variable= "value";
ad2:
optimal solution: migrate from C++ to C

suboptimal solution: change in main.cpp:
Code:
old:
#include "uici.h"
#include "uiciname.h"

new:
extern "C" {
#include "uici.h"
#include "uiciname.h"
}
Note: Perhaps /usr/local/lib64 would be a safer choice to install your own shared objects into.

Last edited by NevemTeve; 06-12-2016 at 10:29 AM.
 
1 members found this post helpful.
Old 06-12-2016, 10:58 AM   #5
trist007
Senior Member
 
Registered: May 2008
Distribution: Slackware
Posts: 1,052

Original Poster
Rep: Reputation: 70
Great that worked thank you NevemTeve. What does the extern "C" do exactly? I know extern names it a global variable but what is happening behind the scenes. How did this satisfy the linker?
 
Old 06-12-2016, 11:00 AM   #6
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,863
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
C++ mangles the external names to make overloading possible.
https://en.wikipedia.org/wiki/Name_mangling#C.2B.2B

This name-mangling can be prevented with extern "C"
 
Old 06-12-2016, 11:10 AM   #7
trist007
Senior Member
 
Registered: May 2008
Distribution: Slackware
Posts: 1,052

Original Poster
Rep: Reputation: 70
Awesome thank you so much!
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
C++, order of included header files in inheritance? michaelinux Programming 2 01-18-2012 02:02 PM
How to check missing header files included from another header file adisan82 Linux - Software 1 01-28-2011 03:57 AM
Undefined Reference ChemicalBurn Programming 2 02-14-2005 03:01 AM
undefined reference to a function included in a library i made!!! keos Programming 5 02-21-2004 04:02 PM
math.h and other included header files ecc6 Slackware 1 04-19-2003 02:15 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:59 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration