gcc — C ++: что перекомпилировать при изменении встроенной функции в динамической библиотеке?

У меня есть две динамические библиотеки и один исполняемый файл:

  • libOtherLibrary.so
    • Это существующая библиотека с открытым исходным кодом, написанная кем-то другим.
  • libMyLibrary.so
    • Это моя собственная библиотека, которая зависит от libOtherLibrary.so.
  • EXE
    • Это мой собственный исполняемый файл, который зависит от обеих библиотек.

В качестве теста, чтобы увидеть, когда вызывается определенная функция, я добавил встроенная функция из libOtherLibrary.so (детали кода не должны иметь значения):

template<class T>
inline void className<T>::clear() const
{
Info << "Hello World!" << endl; // My message!
if (isTmp() && ptr_)
{
if (ptr_->unique())
{
delete ptr_;
ptr_ = 0;
}
else
{
ptr_->operator--();
ptr_ = 0;
}
}
}

Я потом перекомпилировал libOtherLibrary.so, с последующей перекомпиляцией libMyLibrary.so. Наконец-то я перекомпоновывается (так что без перекомпиляции) EXE.

В результате любой вызов className<T>::clear() начато в libMyLibrary.so использовал старый реализация этого встроенного метода, тогда как любой вызов className<T>::clear() по инициативе libOtherLibrary.так использовал новый реализация.

Когда я решил также перекомпилировать EXE (с последующим его связыванием), результатом было то, что новый реализация всегда использовалась.


Мой вопрос: может ли кто-нибудь объяснить мне, почему EXE требуется перекомпиляция, а не перекомпоновка?

То есть встраивание функции className<T>::clear() из libOtherLibrary.so должно происходить на этапе компиляции libMyLibrary.so, не так ли? В конце концов, это функция, содержащаяся в libMyLibrary.so кому звонит className<T>::clear(), Тогда я ожидаю, что связь EXE достаточно, так как EXE не вызывает эту конкретную встроенную функцию. Один компоновщик позаботится о любой измененной совместимости ABI.

2

Решение

Мой вопрос: может кто-нибудь объяснить мне, почему exe требуется
перекомпиляция, а не перекомпоновка
?

Потому что, для вашего конкретного варианта использования, без него вы навлечете на себя гнев Нарушение ODR.


В результате любой вызов className<T>::clear() начато в
libMyLibrary.so использовал старый реализация этого встроенного метода, тогда как любой вызов className<T>::clear() по инициативе
libOtherLibrary.так использовал новый реализация.

Когда у вас есть функция-шаблон сказать:

template<class T>
inline void className<T>::clear(){
....
}

И это ODR используется в нескольких единицах перевода (файл .cpp). Это экземпляр будет определен в каждом из таких единиц перевода, потому что Функции-шаблоны неявно inline,

Правила для такого множественного определения изложены здесь basic.def.odr / 6. И одно из перечисленных требований гласит, что «каждое определение D должно состоять из одной и той же последовательности токенов»;.

Изменение этого шаблона функции и перекомпиляция некоторых модулей перевода, использующих его в ODR, и связывание вашей программы без перекомпиляции все единицы перевода, использующие ODR, нарушают святое Правило Единого Определения C ++.

Наборы инструментов компилятора не обязаны диагностировать это.

2

Другие решения

Еще один способ сказать это:

Предполагая, компилятор делает встраивание (который не связан с inline ключевое слово, например НКУ постараюсь встроить, если вы компилируете и ссылка с g++ -flto -O2 четные функции, которые не отмечен inline), код должен быть перекомпилирован, как только изменится определение встроенной функции. В большинстве хороших программ на C ++ это определение встречается в некоторых заголовок файлы (содержащие явно inline функции).

Поэтому вы должны перекомпилировать при изменении заголовочных файлов. Хорошие инструменты автоматизации сборки (например, make в сочетании с g++ -MD) справиться с этим.

0

По вопросам рекламы [email protected]