C++:当动态库中的内联函数发生变化时要重新编译什么?
C++: What to recompile when an inline function in a dynamic library changes?
我有两个动态库和一个可执行文件:
- libOtherLibrary.so
- 这是别人编写的现有开源库。
- libMyLibrary.so
- 这是我自己的依赖于libOtherLibrary.so.
的库
- exe
- 这是我自己的可执行文件,它依赖于这两个库。
作为查看何时调用特定函数的测试,我向 libOtherLibrary.so[=64 的 内联函数 添加了打印语句=](代码细节无关紧要):
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。最后我relinked(所以没有重新编译)exe.
结果是在 libMyLibrary.so 中发起的对 className<T>::clear()
的任何调用都使用了此的 old 实现内联方法,而任何由 libOtherLibrary 发起的对 className<T>::clear()
的调用。因此使用了 new 实现。
当我随后决定也重新编译 exe(然后链接它)时,结果是始终使用 new 实现.
我的问题是:谁能给我解释一下为什么 exe 需要 重新编译,而不是仅重新链接 ?
即libOtherLibrary.so的函数className<T>::clear()
的内联应该发生在[=92=的编译阶段],不是吗?毕竟是libMyLibrary.so中包含的函数调用className<T>::clear()
。然后我希望链接 exe 就足够了,因为 exe 不会调用这个特定的内联函数。链接器将单独处理任何更改的 ABI 兼容性。
My question is: Can someone explain to me why exe required
recompilation, rather than relinking only?
因为,对于您的特定用例,如果没有它,您将招致 ODR violation 的愤怒。
The result was that any call to className<T>::clear()
initiated in
libMyLibrary.so used the old implementation of this inline method, whereas any call to className<T>::clear()
initiated by
libOtherLibrary.so used the new implementation.
当你有一个函数模板时说:
template<class T>
inline void className<T>::clear(){
....
}
并且在多个翻译单元(.cpp 文件)中是ODR used。它的实例化将在每个这样的翻译单元中定义,因为 function-templates 是隐式的 inline
.
此处说明了此类多重定义的规则basic.def.odr/6。列出的要求之一是 "each definition of D shall consist of the same sequence of tokens;".
修改该函数模板并重新编译一些使用 ODR 的翻译单元,并链接您的程序,而不重新编译所有 使用它的翻译单元 ODR 违反了圣洁C++的一种定义规则。
诊断它不需要编译器工具链。
另一种说法:
假设编译器做 inlining (which is unrelated to inline
keyword, e.g. GCC会努力内联如果你编译和link g++ -flto -O2
即使 不是 标记为 inline
的函数,只要内联函数的定义发生变化,就应该重新编译代码。在大多数优秀的 C++ 程序中,该定义出现在某些 header 文件中(明确包含 inline
函数)。
所以当头文件改变时你应该重新编译。好的构建自动化工具(例如 make
与 g++ -MD
相结合)可以解决这个问题。
我有两个动态库和一个可执行文件:
- libOtherLibrary.so
- 这是别人编写的现有开源库。
- libMyLibrary.so
- 这是我自己的依赖于libOtherLibrary.so. 的库
- exe
- 这是我自己的可执行文件,它依赖于这两个库。
作为查看何时调用特定函数的测试,我向 libOtherLibrary.so[=64 的 内联函数 添加了打印语句=](代码细节无关紧要):
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。最后我relinked(所以没有重新编译)exe.
结果是在 libMyLibrary.so 中发起的对 className<T>::clear()
的任何调用都使用了此的 old 实现内联方法,而任何由 libOtherLibrary 发起的对 className<T>::clear()
的调用。因此使用了 new 实现。
当我随后决定也重新编译 exe(然后链接它)时,结果是始终使用 new 实现.
我的问题是:谁能给我解释一下为什么 exe 需要 重新编译,而不是仅重新链接 ?
即libOtherLibrary.so的函数className<T>::clear()
的内联应该发生在[=92=的编译阶段],不是吗?毕竟是libMyLibrary.so中包含的函数调用className<T>::clear()
。然后我希望链接 exe 就足够了,因为 exe 不会调用这个特定的内联函数。链接器将单独处理任何更改的 ABI 兼容性。
My question is: Can someone explain to me why exe required recompilation, rather than relinking only?
因为,对于您的特定用例,如果没有它,您将招致 ODR violation 的愤怒。
The result was that any call to
className<T>::clear()
initiated in libMyLibrary.so used the old implementation of this inline method, whereas any call toclassName<T>::clear()
initiated by libOtherLibrary.so used the new implementation.
当你有一个函数模板时说:
template<class T>
inline void className<T>::clear(){
....
}
并且在多个翻译单元(.cpp 文件)中是ODR used。它的实例化将在每个这样的翻译单元中定义,因为 function-templates 是隐式的 inline
.
此处说明了此类多重定义的规则basic.def.odr/6。列出的要求之一是 "each definition of D shall consist of the same sequence of tokens;".
修改该函数模板并重新编译一些使用 ODR 的翻译单元,并链接您的程序,而不重新编译所有 使用它的翻译单元 ODR 违反了圣洁C++的一种定义规则。
诊断它不需要编译器工具链。
另一种说法:
假设编译器做 inlining (which is unrelated to inline
keyword, e.g. GCC会努力内联如果你编译和link g++ -flto -O2
即使 不是 标记为 inline
的函数,只要内联函数的定义发生变化,就应该重新编译代码。在大多数优秀的 C++ 程序中,该定义出现在某些 header 文件中(明确包含 inline
函数)。
所以当头文件改变时你应该重新编译。好的构建自动化工具(例如 make
与 g++ -MD
相结合)可以解决这个问题。