неопределенная ссылка на функцию, объявленную в файле * .h - PullRequest
6 голосов
/ 15 сентября 2011

Я неквалифицированный программист и новичок в 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*’

тогда я сливаю их с

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.0 и liblindo64.so с

ln -sf liblindo64.so.6.0 liblindo64.so

но это не помогает.

Может кто-нибудь сказать мне, что здесь не так?

(я не уверен, что мне следует ставить этот вопрос в новом сообщении, но я думаю, что в настоящее время лучше следовать старому)

Ответы [ 4 ]

15 голосов
/ 15 сентября 2011

Хорошо, lindo.h содержит прототипы для этих функций, но где эти функции на самом деле определены? Если они находятся в другом C-файле, вам нужно скомпилировать его и связать оба объектных файла вместе.

Если функции являются частью другой статической библиотеки, вы должны указать компоновщику связать эту библиотеку вместе с вашим объектным файлом.

Если они определены с помощью общей библиотеки, вы, вероятно, можете заставить g ++ по-прежнему ссылаться на нее во время компиляции, а также позаботиться о загрузке библиотеки и т. Д. В противном случае вам потребуется загрузить библиотеку во время выполнения и сослаться на функции из библиотеки. Эта статья в Википедии о динамической загрузке общих библиотек содержит пример кода.

1 голос
/ 15 сентября 2011

Вы должны указать gcc ссылку на библиотеку или объектный файл (ы), которые содержат функции LS ..., которые вы используете.Заголовочный файл сообщает компилятору, как их вызывать, но компоновщик должен знать, откуда взять скомпилированный код.

1 голос
/ 15 сентября 2011

Попробуйте

g ++ -Wall -o ex_addinst ex_addinst. c

вместо

g ++ -Wall -o ex_addinst ex_addinst.o

Вы хотите скомпилировать файл .c, а не файл .o.

0 голосов
/ 15 сентября 2011

undefined reference to ... не является проблемой объявления. Компилятор не работает, потому что он не может найти символы (объекты), которые связаны с этими объявленными функциями.
В вашем случае вы используете Limbo API и включаете заголовочный файл, но не говорите компилятору связываться с библиотекой: поэтому он не находит символы.
РЕДАКТИРОВАТЬ : Я забыл часть, когда вы говорите, что вы новичок в Linux. Для связи с библиотекой вам нужно использовать опции -L / -l в g ++. man g++ всегда хорошо читается, и документация по Лимбо тоже должна быть.

...