如果链接到未使用的库,则可执行文件的构建方式是否不同?

时间:2012-12-21 04:14:35

标签: c++ c++11 shared-libraries static-libraries

除了更长的编译时间,链接未使用的库是否有任何缺点?

例如,在以下两种方式之一编译的程序的可执行文件中是否存在任何差异:

g++ -o main main.cpp
g++ -o main main.cpp -llib1 -llib2 -llib3 -lmore

*实际上不需要库文件来构建main。

我认为没有区别,因为文件大小相同,但我要求确认。

4 个答案:

答案 0 :(得分:14)

取决于。

  1. 如果liblib1.aliblib2.aliblib3.a是静态库,并且没有使用任何符号,那么就没有区别了。

  2. 如果liblib1.soliblib2.soliblib3.so是共享库,则无论是否使用它们,它们都将在运行时加载。您可以使用链接器标志--as-needed来更改此行为,建议使用此标志。

  3. 要检查二进制文件在运行时直接加载哪些共享库,可以在ELF系统上使用readelf

    $ cat main.c
    int main()
    {
        return 0;
    }
    $ gcc main.c
    $ readelf -d a.out | grep NEEDED
     0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
    $ gcc -lpng main.c
    $ readelf -d a.out | grep NEEDED
     0x0000000000000001 (NEEDED)             Shared library: [libpng12.so.0]
     0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
    

    您可以在我的系统上看到-lpnglibpng12.so.0的链接,无论是否实际使用了它的符号。 --as-needed链接器标志修复了这个问题:

    $ gcc -Wl,--as-needed -lpng main.c
    $ readelf -d a.out | grep NEEDED
     0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
    

    备注

    1. {<1}}标志必须在之前指定库。它只会影响它后面出现的库。因此--as-needed不起作用。

    2. gcc -lpng -Wl,--as-needed命令不仅列出了二进制文件直接链接的库,还列出了所有间接依赖项。这可能会根据这些库的编译方式而改变。只有ldd会向您显示您的直接依赖关系,并且只有readelf会向您显示间接依赖关系。

答案 1 :(得分:0)

这取决于您是链接静态库还是共享库。如果要链接静态库,则每次添加时可执行文件的大小都会增加。链接到共享库,不会大大增加可执行文件的大小,只会添加库符号。

答案 2 :(得分:0)

绝对是的。缺点是其他人(或者您将来)会假设由于某种原因需要 库。大多数人不会花时间削减程序的依赖关系,因此它们的列表会增长和增长。

成本与已编译的代码无关,而是与维护和移植程序有关。

答案 3 :(得分:0)

上面有一些非常好的答案。另一个注意事项是“它真正有什么不同”。已经提到的是维护成本(例如当有人安装一个没有Lib3的新操作系统时出现问题,因此用户必须去某个地方找到lib3并安装它,并且因为lib3也需要lib17而你也不是安装后,它为用户增加了更多的工作)。

但是,当你加载二进制文件时,如果你链接到实际没有使用的共享库,系统仍然会查找那些库,如果它们不存在则拒绝加载 - 这会增加时间,并安装噩梦。

加载代码后,它应该没有额外的运行时惩罚。

话虽如此,有时也会有与未使用的库链接的论据。假设您的代码有一个选项USE_FOO,其中FOO功能仅包含在构建时基于某些任意选择(例如“这是在Linux内核&gt; 3.0上”或“系统是否具有花哨的图形卡”),并且FOO使用Lib1做它的业务,它可以使构建系统(makefile或类似)更容易总是链接lib1,即使你没有设置USE_FOO时实际上不需要它。

但总的来说,不要链接不需要的库。它会导致更多的依赖关系,这绝不是一件好事。