我的项目中有三个头文件,它们描述对象Rational
、Complex
和RubyObject
. 前两个是模板。所有这些都可以使用在头文件中定义的复制构造函数进行相互转换——除了那些在源文件中定义的构造Rational
和Complex
from s 的构造函数。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。但是我们在带有 GCC 4.8.1 或 4.8.2 的 Ubuntu 机器上看不到它。但我们确实在装有 4.8.2 的 Mac OS X 机器上看到它——而不是装有 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));
}
需要注意的是,现在我得到了完全相同的错误,但是对于 Complex 对象。啊!
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()
值得一提的是,在调用时(即加载库时)不会发生错误。它发生在很久以后,在另一个调用这些麻烦的函数期间。
我如何一劳永逸地解决这个问题,其他人喜欢它?