Диагностика неопределенных символов при связывании библиотек с исполняемым файлом

#c

#c

Вопрос:

Контекст: я изучаю C по ходу работы, и я нахожусь в точке, где я обнаруживаю, что не могу связать свой проект. Я также нахожу, что диагностика C не самая лучшая, когда дело доходит до точного определения проблем. (Или, по крайней мере, не лучший, учитывая мои знания.)

Я вижу много вопросов StackOverflow по этому поводу, но очень сложно обобщить, если ситуация не соответствует вашему конкретному коду.

Контекст проекта: у меня есть такой проект:

 src
  zmachine
    main.c
    zmachine.h
  terp_cheap
    terp.cheap.c
    terp_cheap.h
  

В каждом из этих каталогов создается статическая библиотека. Затем у меня есть шаг связывания, который берет .a файлы библиотеки и связывает их с исполняемым файлом.

Проблема: все было хорошо, пока я не добавил структуру. Как только я это сделал, при сборке всего проекта этап связывания завершается неудачей:

 COMPLETE: Z-Machine architecture built.
COMPLETE: Cheap Interface built.
gcc  -o quendorc build/zmachine.a build/terp_cheap.a
Undefined symbols for architecture x86_64:
  "_quendor_startup", referenced from:
      _terp_process_arguments in terp_cheap.a(terp_cheap.o)
ld: symbol(s) not found for architecture x86_64
  

Ошибка говорит мне, что я не определил символы (я думаю, это: _quendor_startup ), но, насколько я могу судить, у меня есть.

_quendor_startup То, на что он ссылается, определено в zmachine.h :

 typedef struct quendor_startup_struct {
    char *story_file;
} quendor_startup_t;

extern quendor_startup_t quendor_startup;
  

Обратите внимание, что я также добавляю его туда как quendor_startup .

Основной файл в этой библиотеке ( main.c ) также имеет внешний:

 extern quendor_startup_t quendor_startup;
  

Хотя я даже не уверен, нужно ли мне это. Все это является библиотекой zmachine. Теперь перейдем к библиотеке terp_cheap.

Два файла в этой библиотеке terp_cheap.h и terp_cheap.c также имеют внешний:

 extern quendor_startup_t quendor_startup;
  

terp_cheap Библиотека — это та, с которой компоновщик, похоже, говорит, что проблема. Итак, учитывая вышесказанное, я не уверен, почему это так. Я должен отметить, что включаемый файл для terp_cheap библиотеки ссылается на zmachine.h включение:

 #include "../zmachine/zmachine.h"
  

Таким образом, на структуру в zmachine должна быть возможность ссылаться в terp_cheap библиотеке. То есть я не знаю, куда еще я мог бы поместить внешние файлы.

То, как я использую эту структуру, находится в terp_cheap.c файле, подобном этому:

 void terp_process_arguments( int argc, char *argv[] ) {
  ...
  quendor_startup.story_file = strdup(argv[optind]);
  printf("Loading %s.n", quendor_startup.story_file);
  ...
}
  

Обратите внимание, что эти строки находятся в terp_process_arguments() функции, на которую, похоже, ссылается мой сбой компоновщика.

Итак, что я не вижу, как здесь сделать, так это эффективно диагностировать, почему это происходит. Я знаю, что, по мнению компоновщика, отсутствует. Чего я не понимаю, так это почему он считает, что он отсутствует, учитывая то, что я определил выше.

Вероятна ли ситуация, когда я где-то пропускаю extern? Или, возможно, мое действие ссылки настроено неправильно? Или моя структура выполнена неправильно?

Ответ №1:

На самом деле вы не определили рассматриваемую переменную.

Когда вы делаете это:

 extern quendor_startup_t quendor_startup;
  

У вас есть объявление, означающее, что вы говорите, что переменная где-то существует. Сбой происходит при связывании, потому что это объявление не может быть разрешено.

Вам нужно определить его ровно в одном исходном файле следующим образом:

 quendor_startup_t quendor_startup;
  

Учитывая, что у вас есть объявление в zmachine / zmachine.h, было бы разумно поместить определение в zmachine /main.c . Кроме того, вам не нужно явно добавлять это объявление в другое место, если исходный файл, которому оно требуется, включает zmachine.h .

Комментарии:

1. АХ! Это то, чего мне не хватало. Я понял. В принципе, я поместил эту строку ( quendor_startup_t quendor_startup; ) в свой main.c файл, и все работало нормально. И, да, я только начал задаваться вопросом, не злоупотреблял ли я extern в этом случае. Спасибо за помощь!