在*.h文件中声明的函数未定义引用

9

我是一名不熟练的程序员,对Linux也不熟悉。在编译时遇到了问题。我有两个文件' ex_addinst.c '和' lindo.h '在同一个文件夹中,我输入以下命令:

g++ -c ex_addinst.c

然后,一个名为ex_addinst.o的对象文件被生成,并伴随着一个警告:
ex_addinst.c: In function ‘int main()’:
ex_addinst.c:80: warning: deprecated conversion from string constant to ‘char*’

然后我使用泄漏(leak)它们。
g++ -Wall -o ex_addinst ex_addinst.o

并获取以下信息:

ex_addinst.o: In function `main':
ex_addinst.c:(.text+0x2b): undefined reference to `LSloadLicenseString'
ex_addinst.c:(.text+0x75): undefined reference to `LSgetVersionInfo'
ex_addinst.c:(.text+0xae): undefined reference to `LScreateEnv'
ex_addinst.c:(.text+0x10a): undefined reference to `LSgetErrorMessage'
...
...
ex_addinst.c:(.text+0x1163): undefined reference to `LSdeleteEnv'
collect2: ld returned 1 exit status

我猜测头文件“lindo.h”没有编译进.o文件中,但我现在不知道该怎么做。我已经尝试了gcc,但是出现了相同的错误。我的g++和gcc版本是4.4.5。我正在使用Ubuntu 10.10。
所有函数和结构体都在“lindo.h”中声明。
ex_addinst.c的一部分如下:
    #include <stdio.h>
    #include <stdlib.h>
    /* LINDO API header file */
    #include "lindo.h"
        enter code here
int CALLTYPE LSwriteMPIFile(pLSmodel pModel,
                             char     *pszFname);


/* Define a macro to declare variables for
    error checking */
#define APIERRORSETUP  \
   int nErrorCode; \
   char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH] \
/* Define a macro to do our error checking */
#define APIERRORCHECK  \
   if (nErrorCode) \
   { \
      if ( pEnv) \
      { \
         LSgetErrorMessage( pEnv, nErrorCode, \
          cErrorMessage); \
         printf("nErrorCode=%d:  %s\n", nErrorCode, \
          cErrorMessage); \
      } else {\
         printf( "Fatal Error\n"); \
      } \
      exit(1); \
   } \

#define APIVERSION \
{\
    char szVersion[255], szBuild[255];\
    LSgetVersionInfo(szVersion,szBuild);\
    printf("\nLINDO API Version %s built on %s\n",szVersion,szBuild);\
}\
/* main entry point */
int main()
{
   APIERRORSETUP;
   pLSenv pEnv;
   pLSmodel pModel;
   char MY_LICENSE_KEY[1024];

 /*****************************************************************
  * Step 1: Create a model in the environment.
  *****************************************************************/
   nErrorCode = LSloadLicenseString("home/li/work/tools/lindo/lindoapi/license/lndapi60.lic", MY_LICENSE_KEY);
   if ( nErrorCode != LSERR_NO_ERROR)
   {
      printf( "Failed to load license key (error %d)\n",nErrorCode);
      exit( 1);
   }
......
......
......
   APIERRORCHECK;
   {
      int nStatus;
      double objval=0.0, primal[100];
      /* Get the optimization result */
      nErrorCode = LSgetInfo(pModel, LS_DINFO_GOP_OBJ, &objval);
      APIERRORCHECK;
      LSgetMIPPrimalSolution( pModel, primal) ;
      APIERRORCHECK;
      printf("\n\nObjective = %f \n",objval);
      printf("x[0] = %f \n",primal[0]);
      printf("x[1] = %f \n",primal[1]);
      /* Get the linearity of the solved model */
      nErrorCode = LSgetInfo (pModel, LS_IINFO_GOP_STATUS, &nStatus);
      APIERRORCHECK;
      /* Report the status of solution */
      if (nStatus==LS_STATUS_OPTIMAL || nStatus==LS_STATUS_BASIC_OPTIMAL)
      printf("\nSolution Status: Globally Optimal\n");
      else if (nStatus==LS_STATUS_LOCAL_OPTIMAL)
      printf("\nSolution Status: Locally Optimal\n\n");
      else if (nStatus==LS_STATUS_INFEASIBLE)
      printf("\nSolution Status: Infeasible\n\n");
   }

 /* >>> Step 7 <<< Delete the LINDO environment */
   LSdeleteEnv(&pEnv);

  /* Wait until user presses the Enter key */
   printf("Press <Enter> ...");
   getchar();
}

'lindo.h'的一部分如下:

/*********************************************************************
 * Structure Creation and Deletion Routines (4)                      *
 *********************************************************************/

 pLSenv CALLTYPE LScreateEnv(int     *pnErrorcode,
                             char    *pszPassword);

 pLSmodel CALLTYPE LScreateModel(pLSenv pEnv,
                             int     *pnErrorcode);

 int CALLTYPE LSdeleteEnv(pLSenv *pEnv);


 int CALLTYPE LSdeleteModel(pLSmodel *pModel);


 int CALLTYPE LSloadLicenseString(char *pszFname, char *pachLicense);

 void CALLTYPE LSgetVersionInfo(char *pachVernum, char    *pachBuildDate);

谢谢!


谢谢你们解答我的问题。正如你们建议的那样,在编译时需要链接库。我已经得到了可执行文件:

gcc -o ex_addinst  ./ex_addinst.o -L/home/li/work/tools/lindo/lindoapi/bin/linux64 -m64 -llindo64  -lmosek64 -lconsub3 -lc -ldl -lm -lguide -lpthread -lsvml -limf -lirc

但是当运行可执行文件ex_addinst时,会出现另一个问题:在运行后:
./ex_addinst

以下内容供您参考:

./ex_addinst: error while loading shared libraries: liblindo64.so.6.0: cannot open shared object file: No such file or directory

棘手的问题是,liblindo64.so.6.0在包含以下内容的lib文件夹中:

libconsub3.so  libirc.so          liblindojni.so        libmosek64.so.5.0  lindo.par
libguide.so    liblindo64.so      liblindojni.so.6.0.3  libsvml.so         placeholder
libimf.so      liblindo64.so.6.0  libmosek64.so         lindoapivars.sh    runlindo

我已经使用符号链接在 liblindo64.so.6.0liblindo64.so 之间建立了连接。
ln -sf liblindo64.so.6.0 liblindo64.so

但这并没有帮助。

有人能告诉我这里出了什么问题吗?

(我不确定是否应该在一个新帖子中发布这个问题,但我认为现在最好还是遵循旧的帖子)


你可能在目录树中某个地方有一个名为liblindo.a或类似的文件。您需要将该文件的路径添加到链接器中(使用-Lsomehwere),并使用-llindo链接该库。 - fazo
如果有人正在使用Eclipse,你应该查看以下链接:http://stackoverflow.com/questions/16052148/undefined-reference-to-functions-declared-in-lindo-h?answertab=active#tab-top - mm_
5个回答

21

好的,lindo.h 包含了那些函数的原型,但是这些函数实际上在哪里定义的呢?如果它们在另一个 C 文件中,您需要编译那个文件,并将两个对象文件链接在一起。

如果这些函数属于另一个静态库,您需要告诉链接器将该库与您的对象文件一起链接。

如果它们是使用共享库定义的,则可以在编译时让 g++ 仍然链接到它,并处理库加载等事项。否则,您需要在运行时加载库并从库中引用函数。这篇关于动态加载共享库的维基百科文章包含一些示例代码。


谢谢Praetorian,你说得对,在lindo.h中只有原型,我会寻找它们的定义。 - ulyssis

1

尝试使用

g++ -Wall -o ex_addinst ex_addinst.c

而不是

g++ -Wall -o ex_addinst ex_addinst.o

您需要编译 .c 文件,而不是 .o 文件。


2
在这种情况下,只是链接。它之前已经编译过了(请再次阅读问题)。 - sidyll
他已经编译了源文件(参见第一行代码,gcc -c ...),第二行告诉编译器将对象链接成可执行二进制文件。 - psycho

1

undefined reference to ...不是声明问题。编译器失败是因为它找不到与那些已声明的函数相关的符号(对象)。
在您的情况下,您使用Limbo API并包含头文件,但是您没有告诉编译器链接该库:这就是为什么它找不到符号的原因。
编辑:我忘记了你说你是Linux新手的那部分。要链接库,您需要使用g ++的-L/-l选项。man g++总是一个好的阅读材料,Limbo的文档也应该是。


谢谢 psycho,我已经找到了带有 *.so 文件的库,正在尝试将它们链接起来。 - ulyssis

1

你需要告诉gcc链接库或包含LS ...函数的目标文件。头文件告诉编译器如何调用它们,但链接器需要知道从哪里获取已编译的代码。


0

用于编写和添加头文件:

头文件

//arithmatic.h
#ifndef _ARITHMATIC_H
#define _ARITHMATIC_H

int two_num_sum(int x, int y);

#endif

//arithmatic.c
#include "arithmatic.h"

int two_num_sum(int x, int y){
 return x +y;
}

主文件:
#include<stdio.h>
#include "arithmatic.h"

int main(){
 int sum = two_num_sum(3, 4);
  
  printf("%d",sum);

 return 0

编译:你需要同时编译arithmatic.c文件。
$ gcc arithmatic.c main.c -o sum_program
$./sum_program

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接