0

我正在尝试在 MinGW 下编译 SASL,并且在源文件seterror.c中声明了两个函数,如下所示:


#include <config.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#ifdef HAVE_SYSLOG
#include <syslog.h>
#endif
#include <stdarg.h>
#include <ctype.h>

#include <sasl.h>
#include <saslutil.h>
#include <saslplug.h>
#include "saslint.h"

#ifdef WIN32
/* need to handle the fact that errno has been defined as a function
   in a dll, not an extern int */
# ifdef errno
#  undef errno
# endif /* errno */
#endif /* WIN32 */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

static int _sasl_seterror_usererr(int saslerr)
{
    /* Hide the difference in a username failure and a password failure */
    if (saslerr == SASL_NOUSER)
    return SASL_BADAUTH;

    /* otherwise return the error given; no transform necessary */
    return saslerr;
}

void sasl_seterror(sasl_conn_t *conn,
           unsigned flags,
           const char *fmt, ...)
{
  size_t outlen=0; /* current length of output buffer */
  size_t pos = 0; /* current position in format string */
  size_t formatlen;
  int result;
  sasl_log_t *log_cb = NULL;
  void *log_ctx;
  int ival;
  char *cval;
  va_list ap; /* varargs thing */
  char **error_buf;
  size_t *error_buf_len;

  if(!conn) {
#ifndef SASL_OSX_CFMGLUE
      if(!(flags & SASL_NOLOG)) {
      /* See if we have a logging callback... */
      result = _sasl_getcallback(NULL, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
      if (result == SASL_OK && ! log_cb)
          result = SASL_FAIL;
      if (result != SASL_OK)
          return;

      log_cb(log_ctx, SASL_LOG_FAIL,
         "No sasl_conn_t passed to sasl_seterror");
      }  
#endif /* SASL_OSX_CFMGLUE */
      return;
  } else if(!fmt) return;    

/* we need to use a back end function to get the buffer because the
   cfm glue can't be rooting around in the internal structs */
  _sasl_get_errorbuf(conn, &error_buf, &error_buf_len);

  formatlen = strlen(fmt);

  va_start(ap, fmt); /* start varargs */

  while(pos<formatlen)
  {
    if (fmt[pos]!='%') /* regular character */
    {
      result = _buf_alloc(error_buf, error_buf_len, outlen+1);
      if (result != SASL_OK)
    return;
      (*error_buf)[outlen]=fmt[pos];
      outlen++;
      pos++;
    } else { /* formating thing */
      int done=0;
      char frmt[10];
      int frmtpos=1;
      char tempbuf[21];
      frmt[0]='%';
      pos++;

      while (done==0)
      {
    switch(fmt[pos])
      {
      case 's': /* need to handle this */
        cval = va_arg(ap, char *); /* get the next arg */
        result = _sasl_add_string(error_buf, error_buf_len,
                      &outlen, cval);

        if (result != SASL_OK) /* add the string */
          return;

        done=1;
        break;

      case '%': /* double % output the '%' character */
        result = _buf_alloc(error_buf, error_buf_len, outlen+1);
        if (result != SASL_OK)
          return;
        (*error_buf)[outlen]='%';
        outlen++;
        done=1;
        break;

      case 'm': /* insert the errno string */
        result = _sasl_add_string(error_buf, error_buf_len,
                      &outlen,
                      strerror(va_arg(ap, int)));
        if (result != SASL_OK)
          return;
        done=1;
        break;

      case 'z': /* insert the sasl error string */
        result = _sasl_add_string(error_buf, error_buf_len, &outlen,
             (char *)sasl_errstring(_sasl_seterror_usererr(
                            va_arg(ap, int)),NULL,NULL));
        if (result != SASL_OK)
          return;
        done=1;
        break;

      case 'c':
        frmt[frmtpos++]=fmt[pos];
        frmt[frmtpos]=0;
        tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
        tempbuf[1]='\0';

        /* now add the character */
        result = _sasl_add_string(error_buf, error_buf_len,
                      &outlen, tempbuf);
        if (result != SASL_OK)
          return;
        done=1;
        break;

      case 'd':
      case 'i':
        frmt[frmtpos++]=fmt[pos];
        frmt[frmtpos]=0;
        ival = va_arg(ap, int); /* get the next arg */

        snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
        /* now add the string */
        result = _sasl_add_string(error_buf, error_buf_len,
                      &outlen, tempbuf);
        if (result != SASL_OK)
          return;
        done=1;

        break;
      default: 
        frmt[frmtpos++]=fmt[pos]; /* add to the formating */
        frmt[frmtpos]=0;        
        if (frmtpos>9) 
          done=1;
      }
    pos++;
    if (pos>formatlen)
      done=1;
      }

    }
  }

  (*error_buf)[outlen]='\0'; /* put 0 at end */

  va_end(ap);  

#ifndef SASL_OSX_CFMGLUE
  if(!(flags & SASL_NOLOG)) {
      /* See if we have a logging callback... */
      result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
      if (result == SASL_OK && ! log_cb)
      result = SASL_FAIL;
      if (result != SASL_OK)
      return;

      result = log_cb(log_ctx, SASL_LOG_FAIL, conn->error_buf);
  }
#endif /* SASL_OSX_CFMGLUE */
}

它们周围根本没有#defines。当我编译时:gcc -DHAVE_CONFIG_H -I. -I.. -I../include -I../lib -I../sasldb -I../include -Wall -W -g -O2 -c seterror.cnm 产生:

$ nm seterror.o
00000000 b .bss
00000000 d .data
00000000 N .debug_abbrev
00000000 N .debug_aranges
00000000 N .debug_info
00000000 N .debug_line
00000000 N .debug_loc
00000000 N .debug_ranges
00000000 N .debug_str
00000000 r .eh_frame
00000000 r .rdata
00000000 吨 .text
         U __buf_alloc
         U __imp__sasl_errstring
         U __sasl_add_string
         U __sasl_get_errorbuf
         U __sasl_getcallback
00000000 T _sasl_seterror
         U_snprintf
         U_strerror

为什么没有地址?如果我在库上运行 nm,我会得到:

$ nm .libs/libsasl2.a | grep sasl_seterror
         U __imp__sasl_seterror
         U __imp__sasl_seterror
         U __imp__sasl_seterror
         U __imp__sasl_seterror
         U __imp__sasl_seterror
         U __imp__sasl_seterror
         U __imp__sasl_seterror
00000000 T _sasl_seterror

还是没有地址,为什么?最后,当我尝试链接库时,我收到错误消息undefined reference to '__imp__sasl_seterror'

谁能帮忙解释这里发生了什么?

4

2 回答 2

2
static int _sasl_seterror_usererr(int saslerr);

void sasl_seterror(sasl_conn_t *conn,
           unsigned flags,
           const char *fmt, ...);

它们都没有定义一个函数,他们只声明它。他们承诺您将提供该功能,但自己不提供。结果,当您违反承诺时会出现链接错误。

您需要实际定义函数以获取地址并链接到它。

于 2012-08-13T17:38:58.917 回答
0

有一个标题行链接如下:

LIBSASL_API void sasl_seterror(sasl_conn_t *conn, unsigned flags,
                   const char *fmt, ...);

并被LIBSASL_API定义为:


#ifdef WIN32
#  ifdef LIBSASL_EXPORTS
#   define LIBSASL_API  __declspec(dllexport)
#  else /* LIBSASL_EXPORTS */
#   define LIBSASL_API  __declspec(dllimport)
#  endif /* LIBSASL_EXPORTS */
#else /* WIN32 */
# define LIBSASL_API extern
#endif /* WIN32 */

因此,该函数正在编译,就好像它将被动态链接一样。

然而,nm 仍在为 sasl_seterror 生成 00000000 T,但链接器不再抱怨该函数。

于 2012-08-13T18:42:18.447 回答