C ++:当动态库中的内联函数发生更改时,重新编译的内容是什么?

时间:2017-09-19 12:46:47

标签: c++ gcc dynamic-library recompile inline-functions

我有两个动态库和一个可执行文件:

  • libOtherLibrary.so
    • 这是由其他人编写的现有开源库。
  • libMyLibrary.so
    • 这是我自己的库,依赖于 libOtherLibrary.so
  • EXE
    • 这是我自己的可执行文件,它依赖于两个库。

作为查看特定函数何时被调用的测试,我在 libOtherLibrary.so 内联函数中添加了一个print语句(代码详细信息无关紧要) :

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

结果是,在 libMyLibrary.so 中启动的对className<T>::clear()的任何调用都使用了此内联方法的实现,而对{{1由 libOtherLibrary 启动.so使用 new 实现。

当我决定重新编译 exe (然后链接它)时,结果是始终使用 new 实现。

我的问题是:有人可以向我解释为什么 exe 需要重新编译,而不是只重新链接

也就是说,在 libMyLibrary.so 的编译阶段,应该发生 libOtherLibrary.so 的函数className<T>::clear()的内联,不是吗?毕竟,它是 libMyLibrary.so 中包含的函数,它调用className<T>::clear()。然后我希望链接 exe 就足够了,因为 exe 不会调用这个特定的内联函数。单独的链接器将处理任何改变的ABI兼容性。

2 个答案:

答案 0 :(得分:2)

  

我的问题是:有人可以向我解释为什么需要exe   重新编译,而不是只重新链接

因为,对于您的特定用例,如果没有它,您将会产生ODR violation的愤怒。

  

结果是对className<T>::clear()的任何调用均已启动    libMyLibrary.so 使用了此内联方法的实现,而对className<T>::clear()的任何调用均由    libOtherLibrary .so使用 new 实现。

如果您有功能模板,请说:

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

在多个翻译单元(.cpp文件)中为ODR used。它的实例化将在每个这样的翻译单元中定义,因为 function-templates 是隐含的inline

此处列出了此类多重定义的规则basic.def.odr/6。列出的要求之一指出 &#34; D的每个定义应由相同的令牌序列组成;&#34;

修改该功能模板并重新编译一些翻译单元,使ODR使用它,并链接您的程序,而不重新编译所有翻译单元使ODR使用它违反了C ++的神圣的一个定义规则

不需要编译器工具链来诊断它。

答案 1 :(得分:0)

另一种说法:

假设编译器 inlining(与inline关键字无关,例如GCC如果您编译并链接就会努力内联 g++ -flto -O2甚至函数 标有inline),一旦内联函数的定义发生变化,代码就应该重新编译。在大多数优秀的C ++程序中,该定义出现在一些文件中(包含明确的inline函数)。

因此,您应该在头文件更改时重新编译。良好的构建自动化工具(例如makeg++ -MD相结合)处理该工具。