Понимание происхождения ошибки дублирующего символа компоновщика - PullRequest
21 голосов
/ 25 мая 2011

У меня есть программа на С ++, которая была скомпилирована ранее, но после смешивания с 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 и, как и ожидалось, она успешно перекомпилировалась. Однако, когда я добавил ссылку обратно, она также успешно скомпилировалась и продолжала делать это после очистки объектных файлов. Я все еще не понимаю, почему он не скомпилировался, особенно учитывая, что символы не должны были конфликтовать, я предотвратил дублирование символов и избавился от любых предыдущих / неполных сборок.

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

1 Ответ

46 голосов
/ 25 мая 2011

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

чч :

#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;.

...