2010-12-28 4 views
0

Похоже, что компоновщик GCC не заботится о том, чтобы одна переменная определялась в двух файлах. Я подозреваю, что это причина проблемы, которую вызывает нас сторонняя библиотека.Обнаружение повторяющихся определений переменной в общей библиотеке

Отнесите:

Файл a.cpp содержит:

int foo; 
//do things with it. 

Файл b.cpp содержит:

int foo; 
//do other things with it. 

Файл c.cpp содержит:

extern int foo; 
//do other things with it. 

Все они составлены gcc для .o, а затем связаны как общий объект.

gcc -fPIC -c a.cpp 
gcc -fPIC -c b.cpp 
gcc -fPIC -c c.cpp 
ld *.o -shared -soname,mylib -o mylib 

Компонент не жалуется вообще, но результирующие двоичные ошибки. Мы подозреваем, что существует по крайней мере несколько конфликтов такого рода и они хотели бы найти их. Какие варианты компоновщика позволят нам их обнаружить?

(интересно, если переменные инициализированы (int foo=0) в обоих файлах, это приводит к ошибке).

ответ

0

Кажется, что параметр компилятора -fno-common заставляет все переменные инициализироваться, поэтому он вызывает ошибки при связывании.

1

Удержать сейчас - вы используете foo для двух разных целей в двух файлах? Это, безусловно, приведет к ошибкам во время выполнения. Если foo должен быть глобальным, тогда он должен быть определен только в одном модуле - компоновщик может принять его, но вы все равно получите только одну копию foo. Если он не должен быть глобальным, он должен быть объявлен «static int foo;»

+0

Согласен, часто да. Иногда понимание мотивов оригинальных авторов дает мне головную боль. Иногда бывает, что он статичен, иногда нужно быть внешним, и так далее. –

1

Это серьезная ошибка проектирования в gcc/ld, это не происходит с использованием MSVC. Это не произойдет, связывая программы, только разделяемые библиотеки. Когда вы связываете программу, компоновщик обеспечивает выполнение всех внешних ссылок, по крайней мере, во время соединения. Когда вы связываете общую библиотеку, это не так. Вместо этого внешние ссылки, для которых нет определений, просто оставлены, чтобы болтаться, аргумент (заданный на странице ld man) заключается в том, что символ должен быть разрешен во время загрузки динамически, так что нет никакой точки, проверяющей его. Это также сложно, если вы используете глупую функцию общих библиотек, захватывающих символы из исполняемых файлов.

Ваша программа не будет плохо себя вести. Если вы укажете, что символы в библиотеке должны быть удовлетворены при загрузке, вы получите ошибку времени загрузки, если вы укажете ленивую связь, ошибка все равно произойдет, но только при первом использовании символа (AFAIK!)

Некоторые старые ОС, я считаю, что BSD, например, допускает недопустимые внешние указатели, которые должны быть оставлены как NULL, чтобы вы могли написать «в программе», чтобы проверить, был ли этот символ связан или нет. Linux ld по крайней мере не поддерживает этот AFAIK.

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

Я считаю это очень серьезной ошибкой дизайна и пытался подать отчет об ошибке. В моем собственном продукте мы были счастливы, что смогли построить под Cygwin, потому что под ним используется компоновщик MSVC, который не позволяет этого поведения, в моем коде было найдено много ошибок.

+0

На самом деле, то, о чем вы пишете, это другая проблема, с которой мы столкнулись (но мы каким-то образом получили компилятор, чтобы хотя бы предупредить об этом). Вы имеете в виду ситуацию, например, когда есть 'extern int x;' без 'int x ; 'когда-либо, поэтому, если это указано во время выполнения, определение не найдено. Это другое: есть 'extern int x;' и более одного 'int x;'. –

Смежные вопросы