неопределенная ссылка на функцию, объявленную в файле *.h

Я неквалифицированный программист и новичок в 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. Я использую Убунту 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

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

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

(Я не уверен, что должен помещать этот вопрос в новый пост, но я думаю, что в настоящее время лучше следовать старому)


person ulyssis    schedule 15.09.2011    source источник
comment
у вас, вероятно, есть где-то в дереве каталогов файл с именем liblindo.a или аналогичный. вам нужно добавить путь к этому файлу в компоновщик (с -Lsomewhere) и связать эту библиотеку с -llindo   -  person fazo    schedule 15.09.2011
comment
Кто-то использует eclipse, вы должны посмотреть: stackoverflow.com/questions/16052148/   -  person mm_    schedule 19.04.2013


Ответы (4)


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

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

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

person Praetorian    schedule 15.09.2011
comment
Спасибо Praetorian, вы правы, в lindo.h только прототипы, поищу их определения. - person ulyssis; 15.09.2011

Пытаться

g++ -Wall -o ex_addinst ex_addinst.c

вместо

g++ -Стена -o ex_addinst ex_addinst.o

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

person Pete Wilson    schedule 15.09.2011
comment
В данном случае это просто ссылка. Он был скомпилирован ранее (прочитайте вопрос еще раз). - person sidyll; 15.09.2011
comment
Он уже скомпилировал исходный файл (см. первую строку кода, gcc -c ...), вторая строка указывает компилятору связать объекты в исполняемый двоичный файл. - person psycho; 15.09.2011
comment
Верно! Виноват. Спасибо ребята! - person Pete Wilson; 15.09.2011

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

person Dmitri    schedule 15.09.2011

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

person psycho    schedule 15.09.2011
comment
Спасибо, псих, нашел библиотеку с файлами *.so, пытаюсь их слинковать. - person ulyssis; 16.09.2011