Ошибка привязки ленивых символов: символ не найден

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

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

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

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).

Но это не проблема конкретной версии (как я думал раньше). Мы видим это на Система Travis 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 copy, думая, что, возможно, компилятор оптимизировал то, что мы не хотим оптимизировать. Но это тоже не исправило, к сожалению. Это сделано с оговоркой:

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));
}

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

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() вызывается (т.е. когда библиотека загружена). Это происходит намного позже, во время очередного вызова этих проблемных функций.

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

4

Решение

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

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

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

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

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

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

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

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

Rational, Complex… шаблоны

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

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

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

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

0

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