Отложенная привязка символов не удалась:символ не найден

StackOverflow https://stackoverflow.com//questions/20010041

Вопрос

У меня есть три файла заголовков в моем проекте которые описывают объекты Rational, Complex, и RubyObject.Первые два — шаблоны.Все они могут быть преобразованы с помощью конструкторов копирования, которые определены в файлах заголовков, за исключением тех, которые создают Rational и Complex от const RubyObject&s, которые определены в исходном файле.

Примечание: Эти определения существуют по необходимости.Если они все зайди в заголовки, получишь циклическая зависимость.

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

void nm_init_data() {
    nm::RubyObject obj(INT2FIX(1));
    nm::Rational32 x(obj);
    nm::Rational64 y(obj);
    nm::Rational128 z(obj);
    volatile nm::Complex64 a(obj);
    volatile nm::Complex128 b(obj);
}

а потом вызов nm_init_data() из точки входа в библиотеку в основном исходном файле.Это заставило эти символы быть правильно связаны.

К сожалению, я недавно обновил GCC, и ошибки вернулись.На самом деле, в GCC 4.6 это происходит немного в другом месте. (например, на Travis-CI).

Но это не проблема конкретной версии (как я думал раньше).Мы видим это на Система Трэвиса CI на базе Ubuntu, который работает под управлением GCC 4.6.Но мы не видим этого на машине с Ubuntu ни с GCC 4.8.1, ни с 4.8.2.Но мы делать посмотрите это на машине Mac OS X с версией 4.8.2, а не на той же машине с 4.7.2.Отключение оптимизации тоже не помогает.

Если я побегу nm в моей библиотеке символ определенно не определен:

$ nm tmp/x86_64-darwin13.0.0/nmatrix/2.0.0/nmatrix.bundle |grep RationalIsEC1ERKNS
                 U __ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
00000000004ca460 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache
00000000004ca458 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache_0

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

Также похоже, что конструктор копирования является неопределенным символом для каждой версии Rational шаблон:

__ZN2nm8RationalIiEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIxEC1ERKNS_10RubyObjectE

«Ну вот это странно», — подумал я."Complex64 и Complex128 здесь также называются nm_init_data функция, но они обе разрешаются правильно — и не указаны в nm -u вывод." Поэтому я попробовал добавить volatile перед созданием копии Rational, думая, что, возможно, компилятор оптимизировал что-то, что мы не хотим оптимизировать.Но это, к сожалению, тоже не исправило ситуацию.Так и было, с оговоркой:

void nm_init_data() {
  volatile VALUE t = INT2FIX(1);
  volatile nm::RubyObject obj(t);
  volatile nm::Rational32 x(const_cast<nm::RubyObject&>(obj));
  volatile nm::Rational64 y(const_cast<nm::RubyObject&>(obj));
  volatile nm::Rational128 z(const_cast<nm::RubyObject&>(obj));
  volatile nm::Complex64 a(const_cast<nm::RubyObject&>(obj));
  volatile nm::Complex128 b(const_cast<nm::RubyObject&>(obj));
}

Предостережение в том, что теперь я получаю ту же самую ошибку, но вместо сложных объектов.Ааа!

dyld: lazy symbol binding failed: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
  Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
  Expected in: flat namespace

dyld: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
  Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
  Expected in: flat namespace

Это полный абсурд.Вот определения обеих этих функций в том же исходном файле, что и nm_init_data() функция:

namespace nm {
  template <typename Type>
  Complex<Type>::Complex(const RubyObject& other) {
    // do some things
  }

  template <typename Type>
  Rational<Type>::Rational(const RubyObject& other) {
    // do some other things
  }
} // end of namespace nm

Намекать: Стоит отметить, что ошибка не возникает, когда nm_init_data() вызывается (т. е. когда библиотека загружается).Это происходит гораздо позже, во время очередного вызова этих неприятных функций.

Как мне решить эту проблему раз и навсегда, чтобы она понравилась другим?

Это было полезно?

Решение

Вы утверждаете следующее, в чем я сомневаюсь.

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

В большинстве случаев такую ​​циклическую путаницу можно решить, выделив код в дополнительный файл .hpp, который включается вместе с определением класса и содержит определения шаблонов в любом необходимом месте.

Если ваш код имеет реальную циклическую зависимость, он не сможет скомпилироваться.Обычно, если ваши зависимости кажутся циклическими, вам нужно присмотреться, спуститься на уровень метода и проверить, какой из них потребует компиляции обоих типов.

Таким образом, возможно, ваши типы используют друг друга, а затем компилируют все в один файл .cpp (например,через три .hpp-включения).Или есть только указатель на другой тип, тогда используйте упреждающие объявления, чтобы гарантировать, что все шаблоны разрешены.Или, в-третьих, у вас есть какой-то метод, который зависит от прямого, а какой-то от обратного, затем поместите один тип в один файл, другие — в другой, и все снова в порядке.

Кроме того, похоже, вам следует использовать предварительное объявление для недостающих элементов.Я ожидал бы чего-то вроде следующего после определения функции.Например.:

template nm::Complex<nm::RubyObject>::Complex(const nm::RubyObject& other);

Другие советы

Rational, Complex...шаблоны

копировать конструкторы...определены в файлах заголовков — за исключением тех, которые создают Rational и Complex от const RubyObject&с, которые определены в исходном файле.

И в этом ваша проблема.С Rational и Complex это шаблоны, все их методы должны быть доступны в вашем заголовочном файле.

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

Просто переместите определения Rational(const RubyObject&) и Complex(const RubyObject&) в соответствующие заголовки, и все должно работать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top