Подтвердить что ты не робот

Понимание происхождения дублирующей символьной ошибки компоновщика

У меня есть С++-программа, которая была скомпилирована ранее, но после удаления файлов Jamfiles программа больше не компилируется, а ld выбрала duplicate symbol error. Это продолжалось после последовательного возврата к исходным файлам Jamfiles, запустив bjam clean, удалив объекты вручную и переключившись с clang с gcc переднего конца на gcc 4.2.1 на MacOs 10.6.7.

Упрощенное описание программы состоит в том, что есть main.cpp и четыре файла, a.h,cpp и b.h,cpp, которые скомпилированы в статическую библиотеку, связанную с main.o. Оба параметра main.cpp и b.cpp зависят от файла, содержащего оскорбительный символ off.h, через два разных промежуточных файла, но ни a.h, ни a.cpp никак не зависят от off.h.

Перед тем, как вы спросите, я убедился, что все файлы были обернуты несколькими защитами определений (#ifndef, #define, #endif), и, хотя я нашел файл, который их отсутствовал, он не ссылался на off.h. Что еще более важно, b.h не содержит ничего, что ссылается на off.h, только реализация, b.cpp, ссылается на off.h. Это только меня озадачило.

Чтобы добавить к моей путанице, я смог удалить ссылку на off.h из b.cpp и, как и ожидалось, перекомпилировал ее успешно. Однако, когда я добавил ссылку обратно, она также была скомпилирована успешно и продолжала делать это после очистки объектных файлов. Я все еще в недоумении, почему он не смог скомпилировать, особенно учитывая, что символы не должны были противоречить друг другу, я предотвратил дублирование символов, и я избавился от любых предыдущих/неполных сборок.

Поскольку я смог успешно скомпилировать свою программу, я сомневаюсь, что смогу воспроизвести ее, чтобы проверить любые предложения. Тем не менее, мне любопытно, как это может произойти, и если я буду сталкиваться с этим поведением в будущем, что, если что-либо, кроме того, что я сделал, могу сделать, чтобы исправить это?

4b9b3361

Ответ 1

Это часто является результатом определения объекта в файле заголовка, а не просто его объявления. Рассмотрим:

h.h:

#ifndef H_H_
#define H_H_
int i;
#endif

a.cpp:

#include "h.h"

b.cpp:

#include "h.h"
int main() {}

Это приведет к дублированию символа i. Решение состоит в том, чтобы объявить объект в файле заголовка: extern int i; и определить его в одном из файлов исходного кода: int i;.